<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Paper from 'material-ui/Paper';
import FlatButton from 'material-ui/FlatButton';
import AutoComplete from 'material-ui/AutoComplete';
import presentations from '../../../../data/presentations';
import { cloneDeep } from 'lodash';
import LogoWhite from '../../../../assets/logo-white.svg';
import './index.css';
import Formsy from 'formsy-react';
import { FormsyText } from 'formsy-material-ui/lib';
import { Scrollbars } from 'react-custom-scrollbars';

class Adder extends Component {
  constructor(props) {
    super(props);

    this.state = {
      wpId: '',
      dataSource: [],
      title: '',
      authorName: '',
      version: ''
    };
  }

  componentDidMount() {
    this._isMounted = true;

    presentations
      .list()
      .then(res => {
        if (!this._isMounted) throw new Error('Not mounted');
        return res;
      })
      .then(res =>
        this.setState({
          dataSource: res.map(single => {
            return {
              text: single.title,
              value: single.id
            };
          })
        })
      )
      .catch(err => console.log(err));
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  handleSubmit = data => {
    const { handleCreate } = this.props;
    const copy = cloneDeep(data);
    copy.version = copy.version ? parseInt(copy.version, 10) : 0;
    handleCreate(copy);
  };

  handleSelect = (chosenRequest, index) => {
    const { handleSelect } = this.props;
    const { dataSource } = this.state;
    if (index < 0) return;
    handleSelect(dataSource[index].value);
  };

  render() {
    const errorMessages = {
      select: 'Select a valid presentation',
      title: 'You must enter a valid title',
      authorName: 'You must enter your name(s)',
      wpId: 'You must provide the WikiPathways ID',
      version: 'You can only enter numeric values'
    };

    return (
      <Scrollbars>
        <Paper zDepth={1} className="adder-wrapper">

Pathway Presenter

              Create interactive presentations from pathways on{' '}

                WikiPathways
              .

            <Paper id="alpha-notice">

Alpha Version

                The Pathway Presenter is currently in alpha stage. This means
                that any presentations you create will only be saved locally.
                You cannot share them and can only present via the browser used
                to create the presentation. This will be rectified for the beta
                version.

            </Paper>

Select a Pathway Presentation

            <AutoComplete
              filter={AutoComplete.fuzzyFilter}
              maxSearchResults={5}
              fullWidth={true}
              openOnFocus={true}
              hintText={'Search by title'}
              dataSource={this.state.dataSource}
              onNewRequest={this.handleSelect}
            />
            <Formsy.Form
              onValid={() => this.setState({ canSubmit: true })}
              onInvalid={() => this.setState({ canSubmit: false })}
              onValidSubmit={this.handleSubmit}
              onInvalidSubmit={() => null}
            >

Create a Pathway Presentation

              <FormsyText
                name="title"
                required
                requiredError={errorMessages.title}
                hintText="The TCA Cycle"
                floatingLabelText="Title"
                fullWidth
                updateImmediately
              />
              <FormsyText
                required
                name="authorName"
                requiredError={'You must fill this in'}
                validationError={errorMessages.authorName}
                hintText="Gregor Mendel, Frederick Sanger"
                floatingLabelText="Author Name(s)"
                fullWidth
                updateImmediately
              />
              <FormsyText
                name="wpId"
                required
                validationError={errorMessages.wpId}
                validationErrors={{
                  beginsWithWP:
                    'The WikiPathways ID must begin with WP followed by a number'
                }}
                validations={{
                  beginsWithWP: (values, value) => {
                    const beginning = value.slice(0, 2);
                    const end = value.slice(2);
                    return beginning === 'WP' && !isNaN(end);
                  }
                }}
                hintText="WP78"
                floatingLabelText="WikiPathways ID"
                value={''}
                fullWidth
                updateImmediately
              />
              <FormsyText
                name="version"
                validations="isNumeric"
                validationError={errorMessages.version}
                hintText="Type '0' for latest"
                floatingLabelText="WikiPathways Version (optional)"
                fullWidth
                updateImmediately
              />
              <FlatButton
                label="Create"
                primary={true}
                type="submit"
                fullWidth={true}
                className="create-button"
                disabled={!this.state.canSubmit}
              />
            </Formsy.Form>

        </Paper>
      </Scrollbars>
    );
  }
}

Adder.propTypes = {
  handleCreate: PropTypes.func.isRequired,
  handleSelect: PropTypes.func.isRequired
};

export default Adder;
<commit_msg>more descriptive headers<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Paper from 'material-ui/Paper';
import FlatButton from 'material-ui/FlatButton';
import AutoComplete from 'material-ui/AutoComplete';
import presentations from '../../../../data/presentations';
import { cloneDeep } from 'lodash';
import LogoWhite from '../../../../assets/logo-white.svg';
import './index.css';
import Formsy from 'formsy-react';
import { FormsyText } from 'formsy-material-ui/lib';
import { Scrollbars } from 'react-custom-scrollbars';

class Adder extends Component {
  constructor(props) {
    super(props);

    this.state = {
      wpId: '',
      dataSource: [],
      title: '',
      authorName: '',
      version: ''
    };
  }

  componentDidMount() {
    this._isMounted = true;

    presentations
      .list()
      .then(res => {
        if (!this._isMounted) throw new Error('Not mounted');
        return res;
      })
      .then(res =>
        this.setState({
          dataSource: res.map(single => {
            return {
              text: single.title,
              value: single.id
            };
          })
        })
      )
      .catch(err => console.log(err));
  }

  componentWillUnmount() {
    this._isMounted = false;
  }

  handleSubmit = data => {
    const { handleCreate } = this.props;
    const copy = cloneDeep(data);
    copy.version = copy.version ? parseInt(copy.version, 10) : 0;
    handleCreate(copy);
  };

  handleSelect = (chosenRequest, index) => {
    const { handleSelect } = this.props;
    const { dataSource } = this.state;
    if (index < 0) return;
    handleSelect(dataSource[index].value);
  };

  render() {
    const errorMessages = {
      select: 'Select a valid presentation',
      title: 'You must enter a valid title',
      authorName: 'You must enter your name(s)',
      wpId: 'You must provide the WikiPathways ID',
      version: 'You can only enter numeric values'
    };

    return (
      <Scrollbars>
        <Paper zDepth={1} className="adder-wrapper">

Pathway Presenter

              Create interactive presentations from pathways on{' '}

                WikiPathways
              .

            <Paper id="alpha-notice">

Alpha Version

                The Pathway Presenter is currently in alpha stage. This means
                that any presentations you create will only be saved locally.
                You cannot share them and can only present via the browser used
                to create the presentation. This will be rectified for the beta
                version.

            </Paper>

Select an existing Pathway Presentation

              Find presentations that you already created

            <AutoComplete
              filter={AutoComplete.fuzzyFilter}
              maxSearchResults={5}
              fullWidth={true}
              openOnFocus={true}
              hintText={'Search by title'}
              dataSource={this.state.dataSource}
              onNewRequest={this.handleSelect}
            />
            <Formsy.Form
              onValid={() => this.setState({ canSubmit: true })}
              onInvalid={() => this.setState({ canSubmit: false })}
              onValidSubmit={this.handleSubmit}
              onInvalidSubmit={() => null}
            >

Create a new Pathway Presentation

              <FormsyText
                name="title"
                required
                requiredError={errorMessages.title}
                hintText="The TCA Cycle"
                floatingLabelText="Title"
                fullWidth
                updateImmediately
              />
              <FormsyText
                required
                name="authorName"
                requiredError={'You must fill this in'}
                validationError={errorMessages.authorName}
                hintText="Gregor Mendel, Frederick Sanger"
                floatingLabelText="Author Name(s)"
                fullWidth
                updateImmediately
              />
              <FormsyText
                name="wpId"
                required
                validationError={errorMessages.wpId}
                validationErrors={{
                  beginsWithWP:
                    'The WikiPathways ID must begin with WP followed by a number'
                }}
                validations={{
                  beginsWithWP: (values, value) => {
                    const beginning = value.slice(0, 2);
                    const end = value.slice(2);
                    return beginning === 'WP' && !isNaN(end);
                  }
                }}
                hintText="WP78"
                floatingLabelText="WikiPathways ID"
                value={''}
                fullWidth
                updateImmediately
              />
              <FormsyText
                name="version"
                validations="isNumeric"
                validationError={errorMessages.version}
                hintText="Type '0' for latest"
                floatingLabelText="WikiPathways Version (optional)"
                fullWidth
                updateImmediately
              />
              <FlatButton
                label="Create"
                primary={true}
                type="submit"
                fullWidth={true}
                className="create-button"
                disabled={!this.state.canSubmit}
              />
            </Formsy.Form>

        </Paper>
      </Scrollbars>
    );
  }
}

Adder.propTypes = {
  handleCreate: PropTypes.func.isRequired,
  handleSelect: PropTypes.func.isRequired
};

export default Adder;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import Link from '../Link';
import s from '../VehicleResults/VehicleResults.scss';
import CategorizedResult from '../VehicleResults/CategorizedResult';
import withStyles from '../../decorators/withStyles';
import LuverneStore from '../../stores/LuverneStore';
import CategoryStore from '../../stores/LvCategoryStore';
import connectToStores from 'alt-utils/lib/connectToStores';
// import VehicleStyle from './VehicleStyle';
import Envision from '../VehicleResults/Envision';
import Configurator from '../VehicleResults/Configurator';

@withStyles(s)
@connectToStores
class LuverneResults extends Component {

	static propTypes = {
		className: PropTypes.string,
		activeIndex: PropTypes.number,
		context: PropTypes.shape({
			params: PropTypes.shape({
				year: PropTypes.string,
				make: PropTypes.string,
				model: PropTypes.string,
			}),
			iconMediaVehicle: PropTypes.object,
			iconParts: PropTypes.oneOfType([
				React.PropTypes.object,
				React.PropTypes.array,
			]),
			vehicleParts: PropTypes.array,
		}),
		vehicle: PropTypes.shape({
			base_vehicle: PropTypes.shape({
				year: PropTypes.string,
				make: PropTypes.string,
				model: PropTypes.string,
			}),
			available_years: PropTypes.array,
			available_makes: PropTypes.array,
			available_models: PropTypes.array,
			lookup_category: PropTypes.array,
			products: PropTypes.array,
		}),
		categories: PropTypes.array,
		activeCategory: PropTypes.object,
		fitments: PropTypes.array,
		error: PropTypes.object,
		iconMediaVehicle: PropTypes.object,
		win: PropTypes.object,
	};

	static contextTypes = {
		onSetTitle: PropTypes.func.isRequired,
		onPageNotFound: PropTypes.func.isRequired,
		onSetMeta: PropTypes.func.isRequired,
		seo: PropTypes.func.isRequired,
	};

	constructor() {
		super();
		this.state = {
			context: {},
			activeKey: '0',
			activeCat: 0,
		};
		this.getMatched = this.getMatched.bind(this);
		this.createParentItem = this.createParentItem.bind(this);
	}

	componentWillMount() {
		const base = this.props.context ? this.props.context.params : {};
		let title = 'Vehicle Results';
		if (base.year && base.make && base.model) {
			title = `${base.year} ${base.make} ${base.model} Fitment Results`;
		}
		this.context.onSetTitle(title);
		this.context.onSetMeta('description', title);
		this.context.seo({
			title,
			description: 'ARIES Automotive parts for ' + title,
		});
	}

	static getStores() {
		return [LuverneStore, CategoryStore];
	}

	static getPropsFromStores() {
		return {
			...LuverneStore.getState(),
			...CategoryStore.getState(),
		};
	}

	getMatched() {
		if (
			!this.props.vehicle ||
			!this.props.vehicle.lookup_category ||
			this.props.vehicle.lookup_category.length === 0 ||
			!this.props.categories ||
			this.props.categories.length === 0
		) {
			return ;
		}

		const groups = [];
		const categoriesGroup = {
			children: [],
		};

		if (this.props.categories && this.props.categories.length > 0) {
			this.props.categories.sort((a, b) => a.sort > b.sort);
		}
		// this.props.categories.map((cat) => {
		// 	const tmp = this.createParentItem(cat);
		// 	console.log(tmp);
		// 	categoriesGroup.children = categoriesGroup.children.concat(tmp.children);
		// 	console.log(categoriesGroup.children);
		// });

		this.props.categories.map((cat) => {
			const tmp = this.props.vehicle.lookup_category.filter((t) => t.category.parent_id === cat.id);
			console.log(tmp);
			// categoriesGroup.children = categoriesGroup.children.concat(tmp.children);
			// console.log(categoriesGroup);
		});

		categoriesGroup.children.map((c) => {
			if (!c.children || !c.children.length === 0) {
				return;
			}

			let subs = [];
			(c.children || []).map((cat) => {
				const tmp = this.props.vehicle.lookup_category.filter((t) => t.category.id === cat.cat.id);
				if (tmp.length > 0) {
					subs = subs.concat(tmp);
				}
			});
			if (subs.length > 0) {
				groups.push(
					<CategorizedResult
						activeIndex={this.props.activeIndex}
						parent={c}
						subs={subs}
						fitments={this.props.fitments}
						key={groups.length}
						iconParts={this.props.context.iconParts}
					/>
				);
			}
		});

		return groups;
	}

	createParentItem(cat) {
		if (cat.children && cat.children.length > 0) {
			cat.children.sort((a, b) => a.sort > b.sort);
		}
		const newCat = {
			cat,
			title: cat.title,
			children: cat.children.map(this.createParentItem),
		};

		return newCat;
	}

	render() {
		const matched = this.getMatched();
		return (

<Link to="/" title="Home">Home</Link>

Vehicle Look Up Results

VEHICLE LOOK UP RESULTS

Choose a category below to see the products that fit your vehicle.
						Some products may require the style of the vehicle to be specified.

					{this.props.context.vehicleParts ? <Configurator win={this.props.win} className={s.configurator} context={this.props.context} /> : null}
					{this.props.context.vehicleParts ? <Envision className={s.envision} /> : null}

					{matched}

		);
	}

}

export default LuverneResults;
<commit_msg>Got the categories grouped on the Results page<commit_after>import React, { Component, PropTypes } from 'react';
import Link from '../Link';
import s from '../VehicleResults/VehicleResults.scss';
import CategorizedResult from '../VehicleResults/CategorizedResult';
import withStyles from '../../decorators/withStyles';
import LuverneStore from '../../stores/LuverneStore';
import CategoryStore from '../../stores/LvCategoryStore';
import connectToStores from 'alt-utils/lib/connectToStores';
// import VehicleStyle from './VehicleStyle';
import Envision from '../VehicleResults/Envision';
import Configurator from '../VehicleResults/Configurator';

@withStyles(s)
@connectToStores
class LuverneResults extends Component {

	static propTypes = {
		className: PropTypes.string,
		activeIndex: PropTypes.number,
		context: PropTypes.shape({
			params: PropTypes.shape({
				year: PropTypes.string,
				make: PropTypes.string,
				model: PropTypes.string,
			}),
			iconMediaVehicle: PropTypes.object,
			iconParts: PropTypes.oneOfType([
				React.PropTypes.object,
				React.PropTypes.array,
			]),
			vehicleParts: PropTypes.array,
		}),
		vehicle: PropTypes.shape({
			base_vehicle: PropTypes.shape({
				year: PropTypes.string,
				make: PropTypes.string,
				model: PropTypes.string,
			}),
			available_years: PropTypes.array,
			available_makes: PropTypes.array,
			available_models: PropTypes.array,
			lookup_category: PropTypes.array,
			products: PropTypes.array,
		}),
		categories: PropTypes.array,
		activeCategory: PropTypes.object,
		fitments: PropTypes.array,
		error: PropTypes.object,
		iconMediaVehicle: PropTypes.object,
		win: PropTypes.object,
	};

	static contextTypes = {
		onSetTitle: PropTypes.func.isRequired,
		onPageNotFound: PropTypes.func.isRequired,
		onSetMeta: PropTypes.func.isRequired,
		seo: PropTypes.func.isRequired,
	};

	constructor() {
		super();
		this.state = {
			context: {},
			activeKey: '0',
			activeCat: 0,
		};
		this.getMatched = this.getMatched.bind(this);
		this.createParentItem = this.createParentItem.bind(this);
	}

	componentWillMount() {
		const base = this.props.context ? this.props.context.params : {};
		let title = 'Vehicle Results';
		if (base.year && base.make && base.model) {
			title = `${base.year} ${base.make} ${base.model} Fitment Results`;
		}
		this.context.onSetTitle(title);
		this.context.onSetMeta('description', title);
		this.context.seo({
			title,
			description: 'ARIES Automotive parts for ' + title,
		});
	}

	static getStores() {
		return [LuverneStore, CategoryStore];
	}

	static getPropsFromStores() {
		return {
			...LuverneStore.getState(),
			...CategoryStore.getState(),
		};
	}

	getMatched() {
		if (
			!this.props.vehicle ||
			!this.props.vehicle.lookup_category ||
			this.props.vehicle.lookup_category.length === 0 ||
			!this.props.categories ||
			this.props.categories.length === 0
		) {
			return ;
		}

		const groups = [];
		const categoriesGroup = {
			children: [],
		};

		if (this.props.categories && this.props.categories.length > 0) {
			this.props.categories.sort((a, b) => a.sort > b.sort);
		}
		this.props.categories.map((cat) => {
			console.log(cat);
			const tmp = this.createParentItem(cat);
			categoriesGroup.children = categoriesGroup.children.concat(tmp);
		});

		categoriesGroup.children.map((c) => {
			if (!c.children || !c.children.length === 0) {
				return;
			}

			let subs = [];
			(c.children || []).map((cat) => {
				const tmp = this.props.vehicle.lookup_category.filter((t) => t.category.id === cat.cat.id);
				if (tmp.length > 0) {
					subs = subs.concat(tmp);
				}
			});
			if (subs.length > 0) {
				groups.push(
					<CategorizedResult
						activeIndex={this.props.activeIndex}
						parent={c}
						subs={subs}
						fitments={this.props.fitments}
						key={groups.length}
						iconParts={this.props.context.iconParts}
					/>
				);
			}
		});

		return groups;
	}

	createParentItem(cat) {
		if (cat.children && cat.children.length > 0) {
			cat.children.sort((a, b) => a.sort > b.sort);
		}
		const newCat = {
			cat,
			title: cat.title,
			children: cat.children.map(this.createParentItem),
		};

		return newCat;
	}

	render() {
		const matched = this.getMatched();
		return (

<Link to="/" title="Home">Home</Link>

Vehicle Look Up Results

VEHICLE LOOK UP RESULTS

Choose a category below to see the products that fit your vehicle.
						Some products may require the style of the vehicle to be specified.

					{this.props.context.vehicleParts ? <Configurator win={this.props.win} className={s.configurator} context={this.props.context} /> : null}
					{this.props.context.vehicleParts ? <Envision className={s.envision} /> : null}

					{matched}

		);
	}

}

export default LuverneResults;
<|endoftext|>


<commit_before>'use strict';

angular.module('vlui')
  .directive('functionSelect', function(_, consts, vl, Pills, Logger, Dataset) {
    return {
      templateUrl: 'components/functionselect/functionselect.html',
      restrict: 'E',
      scope: {
        channelId: '=',
        fieldDef: '='
      },
      link: function(scope /*,element, attrs*/) {
        var BIN='bin', COUNT='count', maxbins;

        scope.func = {
          selected: undefined,
          list: {
            aboveFold: [],
            belowFold: [] // could be empty
          },
          isTemporal: false, // for making belowFold timeUnits single-column
          isCount: false // hide "more" & "less" toggle for COUNT
        };

        // functions for T = timeUnits + undefined
        var temporalFunctions = {
          aboveFold: [
            undefined, 'year',
            'quarter', 'month',
            'date','day',
            'hours', 'minutes',
            'seconds', 'milliseconds',
            'yearmonthdate'
          ],
          belowFold: [
            'yearquarter',
            'yearmonth',
            'yearmonthdatehours',
            'yearmonthdatehoursminutes',
            'yearmonthdatehoursminutesseconds',
            'hoursminutes',
            'hoursminutesseconds',
            'minutesseconds',
            'secondsmilliseconds'
          ]
        };

        var cardinalityFilter = function(timeUnit) {
          var field = Pills.get(scope.channelId).field;
          // Convert 'any' channel to '?'.
          var channel = Pills.isAnyChannel(scope.channelId) ? '?' : scope.channelId;
          return !timeUnit || // Don't filter undefined.
            // Remove timeUnits that do not have variation (cardinality <= 1).
            Dataset.schema.timeUnitHasVariation({field: field, channel: channel, timeUnit: timeUnit});
        };

        // timeUnits = T functions - undefined
        var timeUnits = _.pull(_.concat(temporalFunctions.aboveFold, temporalFunctions.belowFold), undefined);

        // functions for Q = aggregates + BIN + undefined - COUNT
        var quantitativeFunctions = {
          aboveFold: [
            undefined, 'bin',
            'min', 'max',
            'mean', 'median',
            'sum'
          ],
          belowFold: [
            'valid', 'missing',
            'distinct', 'modeskew',
            'q1', 'q3',
            'stdev', 'stdevp',
            'variance', 'variancep'
          ] // hide COUNT for Q in the UI because we dedicate it to a special "# Count" field
        };

        // aggregates = Q Functions + COUNT - BIN - undefined
        var aggregates = _.pull(_.concat(quantitativeFunctions.aboveFold, quantitativeFunctions.belowFold, [COUNT]),
          BIN, undefined);

        scope.selectChanged = function() {
          Logger.logInteraction(Logger.actions.FUNC_CHANGE, scope.func.selected);

          var selectedFunc = scope.func.selected;

          var oldPill = Pills.get(scope.channelId),
            pill = _.clone(oldPill),
            type = pill ? pill.type : '',
            isQ = type === vl.type.QUANTITATIVE,
            isT = type === vl.type.TEMPORAL;

          if(!pill){
            return; // not ready
          }

          // reset field def
          // HACK: we're temporarily storing the maxbins in the pill
          pill.bin = selectedFunc === BIN ? {} : undefined;
          pill.aggregate = (isQ && aggregates.indexOf(selectedFunc) !== -1) ? selectedFunc : undefined;
          pill.timeUnit = (isT && timeUnits.indexOf(selectedFunc) !== -1) ? selectedFunc : undefined;

          if(!_.isEqual(oldPill, pill)){
            Pills.set(scope.channelId, pill, true /* propagate change */);
          }
        };

        // when parent objects modify the field
        scope.$watch('fieldDef', function(pill) {
          if (!pill) {
            return;
          }

          var type = pill.field ? pill.type : '';

          // hack: save the maxbins
          if (pill.bin) {
            maxbins = pill.bin.maxbins;
          }

          var isOrdinalShelf = ['row','column','shape'].indexOf(scope.channelId) !== -1,
            isQ = type === vl.type.QUANTITATIVE,
            isT = type === vl.type.TEMPORAL;

          // for making belowFold timeUnits single-column
          scope.func.isTemporal = isT;

          // hide "more" & "less" toggles for COUNT
          scope.func.isCount = pill.field === '*';

          if(pill.field === '*' && pill.aggregate === COUNT){
            scope.func.list.aboveFold=[COUNT];
            scope.func.list.belowFold=[];
            scope.func.selected = COUNT;
          } else {
            // TODO: check supported type based on primitive data?
            if (isT) {
              scope.func.list.aboveFold = temporalFunctions.aboveFold.filter(cardinalityFilter);
              scope.func.list.belowFold = temporalFunctions.belowFold.filter(cardinalityFilter);
            }
            else if (isQ) {
              scope.func.list.aboveFold = quantitativeFunctions.aboveFold;
              scope.func.list.belowFold = quantitativeFunctions.belowFold;
            }

            var defaultVal = (isOrdinalShelf &&
              (isQ && BIN) || (isT && consts.defaultTimeFn)
            ) || undefined;

            var selected = pill.bin ? 'bin' :
              pill.aggregate || pill.timeUnit;

            if (scope.func.list.aboveFold.indexOf(selected) >= 0 || scope.func.list.belowFold.indexOf(selected) >= 0) {
              scope.func.selected = selected;
            } else {
              scope.func.selected = defaultVal;
            }
          }
        }, true);
      }
    };
  });
<commit_msg>Fix undefined bug (#243)<commit_after>'use strict';

angular.module('vlui')
  .directive('functionSelect', function(_, consts, vl, Pills, Logger, Dataset) {
    return {
      templateUrl: 'components/functionselect/functionselect.html',
      restrict: 'E',
      scope: {
        channelId: '=',
        fieldDef: '='
      },
      link: function(scope /*,element, attrs*/) {
        var BIN='bin', COUNT='count', maxbins;

        scope.func = {
          selected: undefined,
          list: {
            aboveFold: [],
            belowFold: [] // could be empty
          },
          isTemporal: false, // for making belowFold timeUnits single-column
          isCount: false // hide "more" & "less" toggle for COUNT
        };

        // functions for T = timeUnits + undefined
        var temporalFunctions = {
          aboveFold: [
            undefined, 'year',
            'quarter', 'month',
            'date','day',
            'hours', 'minutes',
            'seconds', 'milliseconds',
            'yearmonthdate'
          ],
          belowFold: [
            'yearquarter',
            'yearmonth',
            'yearmonthdatehours',
            'yearmonthdatehoursminutes',
            'yearmonthdatehoursminutesseconds',
            'hoursminutes',
            'hoursminutesseconds',
            'minutesseconds',
            'secondsmilliseconds'
          ]
        };

        var cardinalityFilter = function(timeUnit) {

          var pill =  Pills.get(scope.channelId);
          if (!pill) {
            return true;
          }
          var field = pill.field;
          // Convert 'any' channel to '?'.
          var channel = Pills.isAnyChannel(scope.channelId) ? '?' : scope.channelId;
          return !timeUnit || // Don't filter undefined.
            // Remove timeUnits that do not have variation (cardinality <= 1).
            Dataset.schema.timeUnitHasVariation({field: field, channel: channel, timeUnit: timeUnit});
        };

        // timeUnits = T functions - undefined
        var timeUnits = _.pull(_.concat(temporalFunctions.aboveFold, temporalFunctions.belowFold), undefined);

        // functions for Q = aggregates + BIN + undefined - COUNT
        var quantitativeFunctions = {
          aboveFold: [
            undefined, 'bin',
            'min', 'max',
            'mean', 'median',
            'sum'
          ],
          belowFold: [
            'valid', 'missing',
            'distinct', 'modeskew',
            'q1', 'q3',
            'stdev', 'stdevp',
            'variance', 'variancep'
          ] // hide COUNT for Q in the UI because we dedicate it to a special "# Count" field
        };

        // aggregates = Q Functions + COUNT - BIN - undefined
        var aggregates = _.pull(_.concat(quantitativeFunctions.aboveFold, quantitativeFunctions.belowFold, [COUNT]),
          BIN, undefined);

        scope.selectChanged = function() {
          Logger.logInteraction(Logger.actions.FUNC_CHANGE, scope.func.selected);

          var selectedFunc = scope.func.selected;

          var oldPill = Pills.get(scope.channelId),
            pill = _.clone(oldPill),
            type = pill ? pill.type : '',
            isQ = type === vl.type.QUANTITATIVE,
            isT = type === vl.type.TEMPORAL;

          if(!pill){
            return; // not ready
          }

          // reset field def
          // HACK: we're temporarily storing the maxbins in the pill
          pill.bin = selectedFunc === BIN ? {} : undefined;
          pill.aggregate = (isQ && aggregates.indexOf(selectedFunc) !== -1) ? selectedFunc : undefined;
          pill.timeUnit = (isT && timeUnits.indexOf(selectedFunc) !== -1) ? selectedFunc : undefined;

          if(!_.isEqual(oldPill, pill)){
            Pills.set(scope.channelId, pill, true /* propagate change */);
          }
        };

        // when parent objects modify the field
        scope.$watch('fieldDef', function(pill) {
          if (!pill) {
            return;
          }

          var type = pill.field ? pill.type : '';

          // hack: save the maxbins
          if (pill.bin) {
            maxbins = pill.bin.maxbins;
          }

          var isOrdinalShelf = ['row','column','shape'].indexOf(scope.channelId) !== -1,
            isQ = type === vl.type.QUANTITATIVE,
            isT = type === vl.type.TEMPORAL;

          // for making belowFold timeUnits single-column
          scope.func.isTemporal = isT;

          // hide "more" & "less" toggles for COUNT
          scope.func.isCount = pill.field === '*';

          if(pill.field === '*' && pill.aggregate === COUNT){
            scope.func.list.aboveFold=[COUNT];
            scope.func.list.belowFold=[];
            scope.func.selected = COUNT;
          } else {
            // TODO: check supported type based on primitive data?
            if (isT) {
              scope.func.list.aboveFold = temporalFunctions.aboveFold.filter(cardinalityFilter);
              scope.func.list.belowFold = temporalFunctions.belowFold.filter(cardinalityFilter);
            }
            else if (isQ) {
              scope.func.list.aboveFold = quantitativeFunctions.aboveFold;
              scope.func.list.belowFold = quantitativeFunctions.belowFold;
            }

            var defaultVal = (isOrdinalShelf &&
              (isQ && BIN) || (isT && consts.defaultTimeFn)
            ) || undefined;

            var selected = pill.bin ? 'bin' :
              pill.aggregate || pill.timeUnit;

            if (scope.func.list.aboveFold.indexOf(selected) >= 0 || scope.func.list.belowFold.indexOf(selected) >= 0) {
              scope.func.selected = selected;
            } else {
              scope.func.selected = defaultVal;
            }
          }
        }, true);
      }
    };
  });
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {createUserWithEmailAndPassword} from '../../actions/authActions';
import RegistrationForm from './RegistrationForm';
import toastr from 'toastr';

export class RegistrationPage extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      user: {
        email: "",
        password: ""
      },
      saving: false
    };

    this.updateUserState = this.updateUserState.bind(this);
    this.createUser = this.createUser.bind(this);
  }

  updateUserState(event) {
    const field = event.target.name;
    let user = this.state.user;
    user[field] = event.target.value;
    return this.setState({user: user});
  }

  createUser(event) {
    event.preventDefault();

    this.setState({saving: true});

    this.props.actions.createUserWithEmailAndPassword(this.state.user)
      .then((user) => toastr.success('User Created'))
      .catch(error => {
        toastr.error(error.message);
        this.setState({saving: false});
      });
  }

  render() {
    return (
      <RegistrationForm
        onChange={this.updateUserState}
        onSave={this.createUser}
        saving={this.state.saving}
        user={this.state.user}
      />
    );
  }
}

RegistrationPage.propTypes = {
  actions: PropTypes.object.isRequired
};

RegistrationPage.contextTypes = {
  router: PropTypes.object
};

function mapStateToProps(state, ownProps) {
  return {};
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({createUserWithEmailAndPassword}, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(RegistrationPage);
<commit_msg>Pushing the route to feture after login creation<commit_after>import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {createUserWithEmailAndPassword} from '../../actions/authActions';
import RegistrationForm from './RegistrationForm';
import toastr from 'toastr';

export class RegistrationPage extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      user: {
        email: "",
        password: ""
      },
      saving: false
    };

    this.updateUserState = this.updateUserState.bind(this);
    this.createUser = this.createUser.bind(this);
  }

  updateUserState(event) {
    const field = event.target.name;
    let user = this.state.user;
    user[field] = event.target.value;
    return this.setState({user: user});
  }

  createUser(event) {
    event.preventDefault();

    this.setState({saving: true});

    this.props.actions.createUserWithEmailAndPassword(this.state.user)
      .then((user) => {
        toastr.success('User Created');
        this.context.router.push('/newfeature');
      }
      .catch(error => {
        toastr.error(error.message);
        this.setState({saving: false});
      });
  }

  render() {
    return (
      <RegistrationForm
        onChange={this.updateUserState}
        onSave={this.createUser}
        saving={this.state.saving}
        user={this.state.user}
      />
    );
  }
}

RegistrationPage.propTypes = {
  actions: PropTypes.object.isRequired
};

RegistrationPage.contextTypes = {
  router: PropTypes.object
};

function mapStateToProps(state, ownProps) {
  return {};
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({createUserWithEmailAndPassword}, dispatch)
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(RegistrationPage);
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');

var sdk = require('../../../index');
var dis = require('../../../dispatcher');
var Signup = require("../../../Signup");
var ServerConfig = require("../../views/login/ServerConfig");
var MatrixClientPeg = require("../../../MatrixClientPeg");
var RegistrationForm = require("../../views/login/RegistrationForm");
var CaptchaForm = require("../../views/login/CaptchaForm");

var MIN_PASSWORD_LENGTH = 6;

module.exports = React.createClass({
    displayName: 'Registration',

    propTypes: {
        onLoggedIn: React.PropTypes.func.isRequired,
        clientSecret: React.PropTypes.string,
        sessionId: React.PropTypes.string,
        registrationUrl: React.PropTypes.string,
        idSid: React.PropTypes.string,
        customHsUrl: React.PropTypes.string,
        customIsUrl: React.PropTypes.string,
        defaultHsUrl: React.PropTypes.string,
        defaultIsUrl: React.PropTypes.string,
        brand: React.PropTypes.string,
        email: React.PropTypes.string,
        username: React.PropTypes.string,
        guestAccessToken: React.PropTypes.string,
        // registration shouldn't know or care how login is done.
        onLoginClick: React.PropTypes.func.isRequired,
        onCancelClick: React.PropTypes.func
    },

    getInitialState: function() {
        return {
            busy: false,
            errorText: null,
            formVals: {
                email: this.props.email,
            },
        };
    },

    componentWillMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
        // attach this to the instance rather than this.state since it isn't UI
        this.registerLogic = new Signup.Register(
            this.props.customHsUrl, this.props.customIsUrl
        );
        this.registerLogic.setClientSecret(this.props.clientSecret);
        this.registerLogic.setSessionId(this.props.sessionId);
        this.registerLogic.setRegistrationUrl(this.props.registrationUrl);
        this.registerLogic.setIdSid(this.props.idSid);
        this.registerLogic.setGuestAccessToken(this.props.guestAccessToken);
        this.registerLogic.recheckState();
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
    },

    componentDidMount: function() {
        // may have already done an HTTP hit (e.g. redirect from an email) so
        // check for any pending response
        var promise = this.registerLogic.getPromise();
        if (promise) {
            this.onProcessingRegistration(promise);
        }
    },

    onHsUrlChanged: function(newHsUrl) {
        this.registerLogic.setHomeserverUrl(newHsUrl);
    },

    onIsUrlChanged: function(newIsUrl) {
        this.registerLogic.setIdentityServerUrl(newIsUrl);
    },

    onAction: function(payload) {
        if (payload.action !== "registration_step_update") {
            return;
        }
        // If the registration state has changed, this means the
        // user now needs to do something. It would be better
        // to expose the explicitly in the register logic.
        this.setState({
            busy: false
        });
    },

    onFormSubmit: function(formVals) {
        var self = this;
        this.setState({
            errorText: "",
            busy: true,
            formVals: formVals,
        });

        if (formVals.username !== this.props.username) {
            // don't try to upgrade if we changed our username
            this.registerLogic.setGuestAccessToken(null);
        }

        this.onProcessingRegistration(this.registerLogic.register(formVals));
    },

    // Promise is resolved when the registration process is FULLY COMPLETE
    onProcessingRegistration: function(promise) {
        var self = this;
        promise.done(function(response) {
            self.setState({
                busy: false
            });
            if (!response || !response.access_token) {
                console.warn(
                    "FIXME: Register fulfilled without a final response, " +
                    "did you break the promise chain?"
                );
                // no matter, we'll grab it direct
                response = self.registerLogic.getCredentials();
            }
            if (!response || !response.user_id || !response.access_token) {
                console.error("Final response is missing keys.");
                self.setState({
                    errorText: "Registration failed on server"
                });
                return;
            }
            self.props.onLoggedIn({
                userId: response.user_id,
                homeserverUrl: self.registerLogic.getHomeserverUrl(),
                identityServerUrl: self.registerLogic.getIdentityServerUrl(),
                accessToken: response.access_token
            });

            if (self.props.brand) {
                MatrixClientPeg.get().getPushers().done((resp)=>{
                    var pushers = resp.pushers;
                    for (var i = 0; i < pushers.length; ++i) {
                        if (pushers[i].kind == 'email') {
                            var emailPusher = pushers[i];
                            emailPusher.data = { brand: self.props.brand };
                            MatrixClientPeg.get().setPusher(emailPusher).done(() => {
                                console.log("Set email branding to " + self.props.brand);
                            }, (error) => {
                                console.error("Couldn't set email branding: " + error);
                            });
                        }
                    }
                }, (error) => {
                    console.error("Couldn't get pushers: " + error);
                });
            }

        }, function(err) {
            if (err.message) {
                self.setState({
                    errorText: err.message
                });
            }
            self.setState({
                busy: false
            });
            console.log(err);
        });
    },

    onFormValidationFailed: function(errCode) {
        var errMsg;
        switch (errCode) {
            case "RegistrationForm.ERR_PASSWORD_MISSING":
                errMsg = "Missing password.";
                break;
            case "RegistrationForm.ERR_PASSWORD_MISMATCH":
                errMsg = "Passwords don't match.";
                break;
            case "RegistrationForm.ERR_PASSWORD_LENGTH":
                errMsg = `Password too short (min ${MIN_PASSWORD_LENGTH}).`;
                break;
            case "RegistrationForm.ERR_EMAIL_INVALID":
                errMsg = "This doesn't look like a valid email address";
                break;
            case "RegistrationForm.ERR_USERNAME_INVALID":
                errMsg = "User names may only contain letters, numbers, dots, hyphens and underscores.";
                break;
            case "RegistrationForm.ERR_USERNAME_BLANK":
                errMsg = "You need to enter a user name";
                break;
            default:
                console.error("Unknown error code: %s", errCode);
                errMsg = "An unknown error occurred.";
                break;
        }
        this.setState({
            errorText: errMsg
        });
    },

    onCaptchaLoaded: function(divIdName) {
        this.registerLogic.tellStage("m.login.recaptcha", {
            divId: divIdName
        });
        this.setState({
            busy: false // requires user input
        });
    },

    _getRegisterContentJsx: function() {
        var currStep = this.registerLogic.getStep();
        var registerStep;
        switch (currStep) {
            case "Register.COMPLETE":
                break; // NOP
            case "Register.START":
            case "Register.STEP_m.login.dummy":
                // NB. Our 'username' prop is specifically for upgrading
                // a guest account
                registerStep = (
                    <RegistrationForm
                        showEmail={true}
                        defaultUsername={this.state.formVals.username}
                        defaultEmail={this.state.formVals.email}
                        defaultPassword={this.state.formVals.password}
                        guestUsername={this.props.username}
                        minPasswordLength={MIN_PASSWORD_LENGTH}
                        onError={this.onFormValidationFailed}
                        onRegisterClick={this.onFormSubmit} />
                );
                break;
            case "Register.STEP_m.login.email.identity":
                registerStep = (

                        Please check your email to continue registration.

                );
                break;
            case "Register.STEP_m.login.recaptcha":
                registerStep = (
                    <CaptchaForm onCaptchaLoaded={this.onCaptchaLoaded} />
                );
                break;
            default:
                console.error("Unknown register state: %s", currStep);
                break;
        }
        var busySpinner;
        if (this.state.busy) {
            var Spinner = sdk.getComponent("elements.Spinner");
            busySpinner = (
                <Spinner />
            );
        }

        var returnToAppJsx;
        if (this.props.onCancelClick) {
            returnToAppJsx =

                    Return to app

        }

        return (

Create an account

                {registerStep}

{this.state.errorText}

                {busySpinner}
                <ServerConfig ref="serverConfig"
                    withToggleButton={ this.registerLogic.getStep() === "Register.START" }
                    customHsUrl={this.props.customHsUrl}
                    customIsUrl={this.props.customIsUrl}
                    defaultHsUrl={this.props.defaultHsUrl}
                    defaultIsUrl={this.props.defaultIsUrl}
                    onHsUrlChanged={this.onHsUrlChanged}
                    onIsUrlChanged={this.onIsUrlChanged}
                    delayTimeMs={1000} />

                    I already have an account

                { returnToAppJsx }

        );
    },

    render: function() {
        var LoginHeader = sdk.getComponent('login.LoginHeader');
        var LoginFooter = sdk.getComponent('login.LoginFooter');
        return (

                    <LoginHeader />
                    {this._getRegisterContentJsx()}
                    <LoginFooter />

        );
    }
});
<commit_msg>Comment how we're remembering form vals<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');

var sdk = require('../../../index');
var dis = require('../../../dispatcher');
var Signup = require("../../../Signup");
var ServerConfig = require("../../views/login/ServerConfig");
var MatrixClientPeg = require("../../../MatrixClientPeg");
var RegistrationForm = require("../../views/login/RegistrationForm");
var CaptchaForm = require("../../views/login/CaptchaForm");

var MIN_PASSWORD_LENGTH = 6;

module.exports = React.createClass({
    displayName: 'Registration',

    propTypes: {
        onLoggedIn: React.PropTypes.func.isRequired,
        clientSecret: React.PropTypes.string,
        sessionId: React.PropTypes.string,
        registrationUrl: React.PropTypes.string,
        idSid: React.PropTypes.string,
        customHsUrl: React.PropTypes.string,
        customIsUrl: React.PropTypes.string,
        defaultHsUrl: React.PropTypes.string,
        defaultIsUrl: React.PropTypes.string,
        brand: React.PropTypes.string,
        email: React.PropTypes.string,
        username: React.PropTypes.string,
        guestAccessToken: React.PropTypes.string,
        // registration shouldn't know or care how login is done.
        onLoginClick: React.PropTypes.func.isRequired,
        onCancelClick: React.PropTypes.func
    },

    getInitialState: function() {
        return {
            busy: false,
            errorText: null,
            // We remember the values entered by the user because
            // the registration form will be unmounted during the
            // course of registration, but if there's an error we
            // want to bring back the registration form with the
            // values the user enetered still in it. We can keep
            // them in this component's state since this component
            // persist for the duration of the registration process.
            formVals: {
                email: this.props.email,
            },
        };
    },

    componentWillMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
        // attach this to the instance rather than this.state since it isn't UI
        this.registerLogic = new Signup.Register(
            this.props.customHsUrl, this.props.customIsUrl
        );
        this.registerLogic.setClientSecret(this.props.clientSecret);
        this.registerLogic.setSessionId(this.props.sessionId);
        this.registerLogic.setRegistrationUrl(this.props.registrationUrl);
        this.registerLogic.setIdSid(this.props.idSid);
        this.registerLogic.setGuestAccessToken(this.props.guestAccessToken);
        this.registerLogic.recheckState();
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
    },

    componentDidMount: function() {
        // may have already done an HTTP hit (e.g. redirect from an email) so
        // check for any pending response
        var promise = this.registerLogic.getPromise();
        if (promise) {
            this.onProcessingRegistration(promise);
        }
    },

    onHsUrlChanged: function(newHsUrl) {
        this.registerLogic.setHomeserverUrl(newHsUrl);
    },

    onIsUrlChanged: function(newIsUrl) {
        this.registerLogic.setIdentityServerUrl(newIsUrl);
    },

    onAction: function(payload) {
        if (payload.action !== "registration_step_update") {
            return;
        }
        // If the registration state has changed, this means the
        // user now needs to do something. It would be better
        // to expose the explicitly in the register logic.
        this.setState({
            busy: false
        });
    },

    onFormSubmit: function(formVals) {
        var self = this;
        this.setState({
            errorText: "",
            busy: true,
            formVals: formVals,
        });

        if (formVals.username !== this.props.username) {
            // don't try to upgrade if we changed our username
            this.registerLogic.setGuestAccessToken(null);
        }

        this.onProcessingRegistration(this.registerLogic.register(formVals));
    },

    // Promise is resolved when the registration process is FULLY COMPLETE
    onProcessingRegistration: function(promise) {
        var self = this;
        promise.done(function(response) {
            self.setState({
                busy: false
            });
            if (!response || !response.access_token) {
                console.warn(
                    "FIXME: Register fulfilled without a final response, " +
                    "did you break the promise chain?"
                );
                // no matter, we'll grab it direct
                response = self.registerLogic.getCredentials();
            }
            if (!response || !response.user_id || !response.access_token) {
                console.error("Final response is missing keys.");
                self.setState({
                    errorText: "Registration failed on server"
                });
                return;
            }
            self.props.onLoggedIn({
                userId: response.user_id,
                homeserverUrl: self.registerLogic.getHomeserverUrl(),
                identityServerUrl: self.registerLogic.getIdentityServerUrl(),
                accessToken: response.access_token
            });

            if (self.props.brand) {
                MatrixClientPeg.get().getPushers().done((resp)=>{
                    var pushers = resp.pushers;
                    for (var i = 0; i < pushers.length; ++i) {
                        if (pushers[i].kind == 'email') {
                            var emailPusher = pushers[i];
                            emailPusher.data = { brand: self.props.brand };
                            MatrixClientPeg.get().setPusher(emailPusher).done(() => {
                                console.log("Set email branding to " + self.props.brand);
                            }, (error) => {
                                console.error("Couldn't set email branding: " + error);
                            });
                        }
                    }
                }, (error) => {
                    console.error("Couldn't get pushers: " + error);
                });
            }

        }, function(err) {
            if (err.message) {
                self.setState({
                    errorText: err.message
                });
            }
            self.setState({
                busy: false
            });
            console.log(err);
        });
    },

    onFormValidationFailed: function(errCode) {
        var errMsg;
        switch (errCode) {
            case "RegistrationForm.ERR_PASSWORD_MISSING":
                errMsg = "Missing password.";
                break;
            case "RegistrationForm.ERR_PASSWORD_MISMATCH":
                errMsg = "Passwords don't match.";
                break;
            case "RegistrationForm.ERR_PASSWORD_LENGTH":
                errMsg = `Password too short (min ${MIN_PASSWORD_LENGTH}).`;
                break;
            case "RegistrationForm.ERR_EMAIL_INVALID":
                errMsg = "This doesn't look like a valid email address";
                break;
            case "RegistrationForm.ERR_USERNAME_INVALID":
                errMsg = "User names may only contain letters, numbers, dots, hyphens and underscores.";
                break;
            case "RegistrationForm.ERR_USERNAME_BLANK":
                errMsg = "You need to enter a user name";
                break;
            default:
                console.error("Unknown error code: %s", errCode);
                errMsg = "An unknown error occurred.";
                break;
        }
        this.setState({
            errorText: errMsg
        });
    },

    onCaptchaLoaded: function(divIdName) {
        this.registerLogic.tellStage("m.login.recaptcha", {
            divId: divIdName
        });
        this.setState({
            busy: false // requires user input
        });
    },

    _getRegisterContentJsx: function() {
        var currStep = this.registerLogic.getStep();
        var registerStep;
        switch (currStep) {
            case "Register.COMPLETE":
                break; // NOP
            case "Register.START":
            case "Register.STEP_m.login.dummy":
                // NB. Our 'username' prop is specifically for upgrading
                // a guest account
                registerStep = (
                    <RegistrationForm
                        showEmail={true}
                        defaultUsername={this.state.formVals.username}
                        defaultEmail={this.state.formVals.email}
                        defaultPassword={this.state.formVals.password}
                        guestUsername={this.props.username}
                        minPasswordLength={MIN_PASSWORD_LENGTH}
                        onError={this.onFormValidationFailed}
                        onRegisterClick={this.onFormSubmit} />
                );
                break;
            case "Register.STEP_m.login.email.identity":
                registerStep = (

                        Please check your email to continue registration.

                );
                break;
            case "Register.STEP_m.login.recaptcha":
                registerStep = (
                    <CaptchaForm onCaptchaLoaded={this.onCaptchaLoaded} />
                );
                break;
            default:
                console.error("Unknown register state: %s", currStep);
                break;
        }
        var busySpinner;
        if (this.state.busy) {
            var Spinner = sdk.getComponent("elements.Spinner");
            busySpinner = (
                <Spinner />
            );
        }

        var returnToAppJsx;
        if (this.props.onCancelClick) {
            returnToAppJsx =

                    Return to app

        }

        return (

Create an account

                {registerStep}

{this.state.errorText}

                {busySpinner}
                <ServerConfig ref="serverConfig"
                    withToggleButton={ this.registerLogic.getStep() === "Register.START" }
                    customHsUrl={this.props.customHsUrl}
                    customIsUrl={this.props.customIsUrl}
                    defaultHsUrl={this.props.defaultHsUrl}
                    defaultIsUrl={this.props.defaultIsUrl}
                    onHsUrlChanged={this.onHsUrlChanged}
                    onIsUrlChanged={this.onIsUrlChanged}
                    delayTimeMs={1000} />

                    I already have an account

                { returnToAppJsx }

        );
    },

    render: function() {
        var LoginHeader = sdk.getComponent('login.LoginHeader');
        var LoginFooter = sdk.getComponent('login.LoginFooter');
        return (

                    <LoginHeader />
                    {this._getRegisterContentJsx()}
                    <LoginFooter />

        );
    }
});
<|endoftext|>


<commit_before>// http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
"use strict";

/*
 * WebSocket server for the L3GD20 gyroscope
 * Static requests must be prefixed with /data/, like in http://machine:9876/data/console.html
 */

// Optional. You will see this name in eg. 'ps' or 'top' command
process.title = 'node-gyro';

// Port where we'll run the websocket server
var port = 9876;

// websocket and http servers
var webSocketServer = require('websocket').server;
var http = require('http');
var fs = require('fs');

var verbose = false;

if (typeof String.prototype.startsWith !== 'function') {
  String.prototype.startsWith = function (str)  {
    return this.indexOf(str) == 0;
  };
}

if (typeof String.prototype.endsWith !== 'function') {
  String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
  };
}

// HTTP Handler
var handler = function(req, res) {
  var respContent = "";
  if (verbose === true) {
    console.log("Speaking HTTP from " + __dirname);
    console.log("Server received an HTTP Request:\n" + req.method + "\n" + req.url + "\n-------------");
    console.log("ReqHeaders:" + JSON.stringify(req.headers, null, '\t'));
    console.log('Request:' + req.url);
    var prms = require('url').parse(req.url, true);
    console.log(prms);
    console.log("Search: [" + prms.search + "]");
    console.log("-------------------------------");
  }
  if (req.url.startsWith("/data/")) { // Static resource
    var resource = req.url.substring("/data/".length);
    if (resource.indexOf("?") > -1) {
      resource = resource.substring(0, resource.indexOf("?"));
    }
    console.log('Loading static ' + req.url + " (" + resource + ")");
    fs.readFile(__dirname + '/' + resource,
                function (err, data) {
                  if (err) {
                    res.writeHead(500);
                    return res.end('Error loading ' + resource);
                  }
               // if (verbose)
               //   console.log("Read resource content:\n---------------\n" + data + "\n--------------");
                  var contentType = "text/html";
                  if (resource.endsWith(".css"))
                    contentType = "text/css";
                  else if (resource.endsWith(".html"))
                    contentType = "text/html";
                  else if (resource.endsWith(".xml"))
                    contentType = "text/xml";
                  else if (resource.endsWith(".js"))
                    contentType = "text/javascript";
                  else if (resource.endsWith(".jpg"))
                    contentType = "image/jpg";
                  else if (resource.endsWith(".gif"))
                    contentType = "image/gif";
                  else if (resource.endsWith(".png"))
                    contentType = "image/png";
                  else if (resource.endsWith(".ico"))
                    contentType = "image/ico";

                  res.writeHead(200, {'Content-Type': contentType});
              //  console.log('Data is ' + typeof(data));
                  if (resource.endsWith(".jpg") ||
                      resource.endsWith(".gif") ||
                      resource.endsWith(".ico") ||
                      resource.endsWith(".png"))
                  {
                //  res.writeHead(200, {'Content-Type': 'image/gif' });
                    res.end(data, 'binary');
                  }
                  else
                    res.end(data.toString().replace('$PORT$', port.toString())); // Replace $PORT$ with the actual port value.
                });
  } else if (req.url == "/") {
    if (req.method === "POST") {
      var data = "";
      console.log("---- Headers ----");
      for (var item in req.headers)
        console.log(item + ": " + req.headers[item]);
      console.log("-----------------");

      req.on("data", function(chunk) {
        data += chunk;
      });

      req.on("end", function() {
        console.log("POST request: [" + data + "]");
        res.writeHead(200, {'Content-Type': 'application/json'});
        var status = {'status':'OK'};
        res.end(JSON.stringify(status));
      });
    }
  } else {
    console.log("Un-managed request: [" + req.url + "]");
  //console.log(">>> " + JSON.stringify(req, null, 2));
    respContent = "Response from " + req.url;
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end(); // respContent);
  }
}; // HTTP Handler

/**
 * Global variables
 */
// list of currently connected clients
var clients = [ ];

/**
 * Helper function for escaping input strings
 */
var htmlEntities = function(str) {
  return String(str).replace(/&/g, '&').replace(/</g, '<')
                    .replace(/>/g, '>').replace(/"/g, '"');
};

/**
 * HTTP server
 */
var server = http.createServer(handler);
server.listen(port, function() {
  console.log((new Date()) + " Server is listening on port " + port);
  console.log("Connect to [http://localhost:9876/data/demos/gyro.one.html]");
});

/**
 * WebSocket server
 */
var wsServer = new webSocketServer({
  // WebSocket server is tied to a HTTP server. WebSocket request is just
  // an enhanced HTTP request. For more info http://tools.ietf.org/html/rfc6455#page-6
  httpServer: server
});

// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
  console.log((new Date()) + ' Connection from origin ' + request.origin + '.');

  // accept connection - you should check 'request.origin' to make sure that
  // client is connecting from your website
  // (http://en.wikipedia.org/wiki/Same_origin_policy)
  var connection = request.accept(null, request.origin);
  clients.push(connection);
  console.log((new Date()) + ' Connection accepted.');

  // user sent some message
  connection.on('message', function(message) {
//  console.log("On Message:" + JSON.stringify(message));

    if (message.type === 'utf8') { // accept only text
//    console.log((new Date()) + ' Received Message: ' + message.utf8Data);
//    console.log("Rebroadcasting: " + message.utf8Data);
      for (var i=0; i < clients.length; i++) {
        clients[i].sendUTF(message.utf8Data);
      }
    }
  });

  // user disconnected
  connection.on('close', function(code) {
    // Close
    console.log((new Date()) + ' Connection closed.');
    var nb = clients.length;
    for (var i=0; i<clients.length; i++) {
      if (clients[i] === connection) {
        clients.splice(i, 1);
        break;
      }
    }
    if (verbose) {
      console.log("We have (" + nb + "->) " + clients.length + " client(s) connected.");
    }
  });
});

var broadcastGyroData = function(x, y, z) {
  var mess = { x: x, y: y, z: z };
  for (var i=0; i < clients.length; i++) {
    clients[i].sendUTF(JSON.stringify(mess));
  }
};

// Gyro Sensor
var L3GD20 = require('./l3gd20.js').L3GD20;
var L3GD20Dictionaries = require('./utils/L3GD20Dictionaries.js').L3GD20Dictionaries;

var l3gd20 = new L3GD20();

console.log("Init...")
try {
  l3gd20.open();
  l3gd20.setPowerMode(L3GD20Dictionaries.NORMAL);
  l3gd20.setFullScaleValue(L3GD20Dictionaries._250_DPS);
  l3gd20.setAxisXEnabled(true);
  l3gd20.setAxisYEnabled(true);
  l3gd20.setAxisZEnabled(true);
} catch (err) {
  console.log(err);
  process.exit();
}
console.log("Starting...");
l3gd20.init();
l3gd20.calibrate();

var prevX, prevY, prevZ;

var minX = 0, maxX = 0, minY = 0, maxY = 0, minZ = 0, maxZ = 0;

var iv = setInterval(function () {
  var data = l3gd20.getCalOutValue();
  var x = data[0], y = data[1], z = data[2];
  if (x !== prevX || y !== prevY || z !== prevZ) {
    broadcastGyroData(x, y, z);
  }
  minX = Math.min(x, minX); maxX = Math.max(x, maxX);
  minY = Math.min(y, minY); maxY = Math.max(y, maxY);
  minZ = Math.min(z, minZ); maxZ = Math.max(z, maxZ);
  prevX = x; prevY = y; prevZ = z;
}, 20);

// cleanup on exit
var exit = function() {
  console.log("Bye!");
  l3gd20.shutdown();
  console.log("x in [" + minX + ", " + maxX +
           "], y in [" + minY + ", " + maxY +
           "], z in [" + minZ + ", " + maxZ + "]");
  process.exit();
}
process.on('SIGINT', exit); // Ctrl C
<commit_msg>After the night<commit_after>// http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
"use strict";

/*
 * WebSocket server for the L3GD20 gyroscope
 * WebSocket doc at https://www.npmjs.com/package/websocket
 * Static requests must be prefixed with /data/, like in http://machine:9876/data/demos/gyro.one.html
 */
process.title = 'node-gyro'; // Optional. You will see this name in eg. 'ps' or 'top' command

// Port where we'll run the websocket server
var port = 9876;

// websocket and http servers
var webSocketServer = require('websocket').server;
var http = require('http');
var fs = require('fs');

var verbose = false;

if (typeof String.prototype.startsWith !== 'function') {
  String.prototype.startsWith = function (str)  {
    return this.indexOf(str) === 0;
  };
}

if (typeof String.prototype.endsWith !== 'function') {
  String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
  };
}

// HTTP Handler
var handler = function(req, res) {
  var respContent = "";
  if (verbose === true) {
    console.log("Speaking HTTP from " + __dirname);
    console.log("Server received an HTTP Request:\n" + req.method + "\n" + req.url + "\n-------------");
    console.log("ReqHeaders:" + JSON.stringify(req.headers, null, '\t'));
    console.log('Request:' + req.url);
    var prms = require('url').parse(req.url, true);
    console.log(prms);
    console.log("Search: [" + prms.search + "]");
    console.log("-------------------------------");
  }
  if (req.url.startsWith("/data/")) { // Static resource
    var resource = req.url.substring("/data/".length);
    if (resource.indexOf("?") > -1) {
      resource = resource.substring(0, resource.indexOf("?"));
    }
    console.log('Loading static ' + req.url + " (" + resource + ")");
    fs.readFile(__dirname + '/' + resource,
                function (err, data) {
                  if (err) {
                    res.writeHead(500);
                    return res.end('Error loading ' + resource);
                  }
               // if (verbose)
               //   console.log("Read resource content:\n---------------\n" + data + "\n--------------");
                  var contentType = "text/html";
                  if (resource.endsWith(".css"))
                    contentType = "text/css";
                  else if (resource.endsWith(".html"))
                    contentType = "text/html";
                  else if (resource.endsWith(".xml"))
                    contentType = "text/xml";
                  else if (resource.endsWith(".js"))
                    contentType = "text/javascript";
                  else if (resource.endsWith(".jpg"))
                    contentType = "image/jpg";
                  else if (resource.endsWith(".gif"))
                    contentType = "image/gif";
                  else if (resource.endsWith(".png"))
                    contentType = "image/png";
                  else if (resource.endsWith(".ico"))
                    contentType = "image/ico";

                  res.writeHead(200, {'Content-Type': contentType});
              //  console.log('Data is ' + typeof(data));
                  if (resource.endsWith(".jpg") ||
                      resource.endsWith(".gif") ||
                      resource.endsWith(".ico") ||
                      resource.endsWith(".png"))
                  {
                //  res.writeHead(200, {'Content-Type': 'image/gif' });
                    res.end(data, 'binary');
                  }
                  else
                    res.end(data.toString().replace('$PORT$', port.toString())); // Replace $PORT$ with the actual port value.
                });
  } else if (req.url == "/") {
    if (req.method === "POST") {
      var data = "";
      console.log("---- Headers ----");
      for (var item in req.headers)
        console.log(item + ": " + req.headers[item]);
      console.log("-----------------");

      req.on("data", function(chunk) {
        data += chunk;
      });

      req.on("end", function() {
        console.log("POST request: [" + data + "]");
        res.writeHead(200, {'Content-Type': 'application/json'});
        var status = {'status':'OK'};
        res.end(JSON.stringify(status));
      });
    }
  } else {
    console.log("Un-managed request: [" + req.url + "]");
  //console.log(">>> " + JSON.stringify(req, null, 2));
    respContent = "Response from " + req.url;
    res.writeHead(404, {'Content-Type': 'text/plain'});
    res.end(); // respContent);
  }
}; // HTTP Handler

var clients = []; // list of currently connected clients

/**
 * HTTP server
 */
var server = http.createServer(handler);
server.listen(port, function() {
  console.log((new Date()) + " Server is listening on port " + port);
  console.log("Connect to [http://localhost:9876/data/demos/gyro.one.html]");
});

/**
 * WebSocket server
 */
var wsServer = new webSocketServer({
  // WebSocket server is tied to a HTTP server. WebSocket request is just
  // an enhanced HTTP request. For more info http://tools.ietf.org/html/rfc6455#page-6
  httpServer: server
});

// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
  console.log((new Date()) + ' Connection from origin ' + request.origin + '.');

  // accept connection - you should check 'request.origin' to make sure that
  // client is connecting from your website
  // (http://en.wikipedia.org/wiki/Same_origin_policy)
  var connection = request.accept(null, request.origin);
  clients.push(connection);
  console.log((new Date()) + ' Connection accepted.');

  // user sent some message
  connection.on('message', function(message) {
    if (message.type === 'utf8') { // accept only text
      for (var i=0; i < clients.length; i++) {
        clients[i].sendUTF(message.utf8Data);
      }
    }
  });

  // user disconnected
  connection.on('close', function(code) {
    // Close
    console.log((new Date()) + ' Connection closed.');
    var nb = clients.length;
    for (var i=0; i<clients.length; i++) {
      if (clients[i] === connection) {
        clients.splice(i, 1);
        break;
      }
    }
    if (verbose) {
      console.log("We have (" + nb + "->) " + clients.length + " client(s) connected.");
    }
  });
});

// Called by the gyroscope (below)
var broadcastGyroData = function(x, y, z) {
  var mess = { x: x, y: y, z: z };
  for (var i=0; i < clients.length; i++) {
    clients[i].sendUTF(JSON.stringify(mess));
  }
};

// Gyro Sensor part
var L3GD20 = require('./l3gd20.js').L3GD20;
var L3GD20Dictionaries = require('./utils/L3GD20Dictionaries.js').L3GD20Dictionaries;

var l3gd20 = new L3GD20();

console.log("Init...")
try {
  l3gd20.open();
  l3gd20.setPowerMode(L3GD20Dictionaries.NORMAL);
  l3gd20.setFullScaleValue(L3GD20Dictionaries._250_DPS);
  l3gd20.setAxisXEnabled(true);
  l3gd20.setAxisYEnabled(true);
  l3gd20.setAxisZEnabled(true);
} catch (err) {
  console.log(err);
  process.exit();
}
console.log("Starting...");
l3gd20.init();
l3gd20.calibrate();

var prevX, prevY, prevZ;

var minX = 0, maxX = 0, minY = 0, maxY = 0, minZ = 0, maxZ = 0;

var iv = setInterval(function () {
  var data = l3gd20.getCalOutValue();
  var x = data[0], y = data[1], z = data[2];
  if (x !== prevX || y !== prevY || z !== prevZ) {
    broadcastGyroData(x, y, z); // Invoke the client
  }
  minX = Math.min(x, minX); maxX = Math.max(x, maxX);
  minY = Math.min(y, minY); maxY = Math.max(y, maxY);
  minZ = Math.min(z, minZ); maxZ = Math.max(z, maxZ);
  prevX = x; prevY = y; prevZ = z;
}, 20);

// cleanup on exit
var exit = function() {
  console.log("Bye!");
  l3gd20.shutdown();
  console.log("x in [" + minX + ", " + maxX +
           "], y in [" + minY + ", " + maxY +
           "], z in [" + minZ + ", " + maxZ + "]");
  process.exit();
}
process.on('SIGINT', exit); // Ctrl C
<|endoftext|>


<commit_before>/*global bespoke:true */

(function(bespoke) {
    "use strict";

    bespoke.horizontal.from("article", {
        convenient: true
    });
}(bespoke));
<commit_msg>Remove convenient plugin per deck activation from demo<commit_after>/*global bespoke:true */

(function(bespoke) {
    "use strict";

    bespoke.horizontal.from("article");
}(bespoke));
<|endoftext|>


<commit_before>(function() {

  var el = document.querySelector('.item');
  var status  = document.querySelector('.status');

  function text(el, content) {
    el.innerText = content;
  }

  function html(el, content) {
    el.innerHTML = content;
  }

  function statusHtml(content) {
    html(status, content);
  }

  var inView = InView(el, function(isInView, data) {
    if (isInView) {
      if (data.elementOffsetTopInViewHeight < data.inViewHeight/2) {
        statusHtml('status: in view (top half)');
      } else {
        statusHtml('status: in view (bottom half)');
      }
    } else {
      if (data.windowScrollTop - (data.elementOffsetTop - data.inViewHeight) > data.inViewHeight) {
        statusHtml('status: not in view (scroll up)');
      } else {
        statusHtml('status: not in view (scroll down)');
      }
    }
  });

})();
<commit_msg>update demo<commit_after>(function() {

  var el = document.querySelector('.item');
  var status  = document.querySelector('.status');

  function text(el, content) {
    el.innerText = content;
  }

  function html(el, content) {
    el.innerHTML = content;
  }

  function statusHtml(content) {
    html(status, content);
  }

  var inView = InView(el, function(isInView, data) {
    el.textContent = data.elementOffsetTopInViewHeight;
    if (isInView) {
      if (data.elementOffsetTopInViewHeight < data.inViewHeight/2) {
        statusHtml('status: in view (top half)');
      } else {
        statusHtml('status: in view (bottom half)');
      }
    } else {
      if (data.windowScrollTop - (data.elementOffsetTop - data.inViewHeight) > data.inViewHeight) {
        statusHtml('status: not in view (scroll up)');
      } else {
        statusHtml('status: not in view (scroll down)');
      }
    }
  });

})();
<|endoftext|>


<commit_before>import * as d3 from 'd3/build/d3';

import eventDrops from '../src';
import '../src/style.css';
import { gravatar, humanizeDate } from './utils';

const repositories = require('./data.json');

const numberCommitsContainer = document.getElementById('numberCommits');
const zoomStart = document.getElementById('zoomStart');
const zoomEnd = document.getElementById('zoomEnd');

const updateCommitsInformation = chart => {
    const filteredData = chart
        .filteredData()
        .reduce((total, repo) => total.concat(repo.data), []);

    numberCommitsContainer.textContent = filteredData.length;
    zoomStart.textContent = humanizeDate(chart.scale().domain()[0]);
    zoomEnd.textContent = humanizeDate(chart.scale().domain()[1]);
};

const tooltip = d3
    .select('body')
    .append('div')
    .classed('tooltip', true)
    .style('opacity', 0);

const chart = eventDrops({
    d3,
    zoom: {
        onZoomEnd: () => updateCommitsInformation(chart),
    },
    drop: {
        date: d => new Date(d.date),
        onMouseOver: commit => {
            tooltip
                .transition()
                .duration(200)
                .style('opacity', 1);

            tooltip
                .html(
                    `

${commit.message}

                            ${commit.author.name}
                            on ${humanizeDate(
                                new Date(commit.date)
                            )} -
                            ${commit.sha.substr(0, 10)}

                `
                )
                .style('left', `${d3.event.pageX - 30}px`)
                .style('top', `${d3.event.pageY + 20}px`);
        },
        onMouseOut: () => {
            tooltip
                .transition()
                .duration(500)
                .style('opacity', 0);
        },
    },
});

const repositoriesData = repositories.map(repository => ({
    name: repository.name,
    data: repository.commits,
}));

d3
    .select('#eventdrops-demo')
    .data([repositoriesData])
    .call(chart);

updateCommitsInformation(chart);
<commit_msg>Fixed: Invisible tooltip capturing mouse events and prevents zooming of the timeline.<commit_after>import * as d3 from 'd3/build/d3';

import eventDrops from '../src';
import '../src/style.css';
import { gravatar, humanizeDate } from './utils';

const repositories = require('./data.json');

const numberCommitsContainer = document.getElementById('numberCommits');
const zoomStart = document.getElementById('zoomStart');
const zoomEnd = document.getElementById('zoomEnd');

const updateCommitsInformation = chart => {
    const filteredData = chart
        .filteredData()
        .reduce((total, repo) => total.concat(repo.data), []);

    numberCommitsContainer.textContent = filteredData.length;
    zoomStart.textContent = humanizeDate(chart.scale().domain()[0]);
    zoomEnd.textContent = humanizeDate(chart.scale().domain()[1]);
};

const tooltip = d3
    .select('body')
    .append('div')
    .classed('tooltip', true)
    .style('opacity', 0)
    .style('pointer-events', 'auto');

const chart = eventDrops({
    d3,
    zoom: {
        onZoomEnd: () => updateCommitsInformation(chart),
    },
    drop: {
        date: d => new Date(d.date),
        onMouseOver: commit => {
            tooltip
                .transition()
                .duration(200)
                .style('opacity', 1)
                .style('pointer-events', 'auto');

            tooltip
                .html(
                    `

${commit.message}

                            ${commit.author.name}
                            on ${humanizeDate(
                                new Date(commit.date)
                            )} -
                            ${commit.sha.substr(0, 10)}

                `
                )
                .style('left', `${d3.event.pageX - 30}px`)
                .style('top', `${d3.event.pageY + 20}px`);
        },
        onMouseOut: () => {
            tooltip
                .transition()
                .duration(500)
                .style('opacity', 0)
                .style('pointer-events', 'none');
        },
    },
});

const repositoriesData = repositories.map(repository => ({
    name: repository.name,
    data: repository.commits,
}));

d3
    .select('#eventdrops-demo')
    .data([repositoriesData])
    .call(chart);

updateCommitsInformation(chart);
<|endoftext|>


<commit_before>/* @flow */

import { emptyObject } from 'core/util/index'

export function normalizeScopedSlots (slots: { [key: string]: Function }) {
  if (!slots) {
    return emptyObject
  } else if (slots._normalized) {
    return slots
  } else {
    const res = {}
    for (const key in slots) {
      res[key] = normalizeScopedSlot(slots[key])
    }
    res._normalized = true
    return res
  }
}

function normalizeScopedSlot(fn: Function) {
  return scope => {
    const res = fn(scope)
    return Array.isArray(res) ? res : res ? [res] : res
  }
}
<commit_msg>chore: fix types<commit_after>/* @flow */

import { emptyObject } from 'core/util/index'

export function normalizeScopedSlots (slots: { [key: string]: Function } | void): any {
  if (!slots) {
    return emptyObject
  } else if (slots._normalized) {
    return slots
  } else {
    const res = {}
    for (const key in slots) {
      res[key] = normalizeScopedSlot(slots[key])
    }
    res._normalized = true
    return res
  }
}

function normalizeScopedSlot(fn: Function) {
  return scope => {
    const res = fn(scope)
    return Array.isArray(res) ? res : res ? [res] : res
  }
}
<|endoftext|>


<commit_before>define(
  'ephox.sugar.api.selection.WindowSelection',

  [
    'ephox.katamari.api.Option',
    'ephox.sugar.api.dom.DocumentPosition',
    'ephox.sugar.api.node.Element',
    'ephox.sugar.api.node.Fragment',
    'ephox.sugar.api.search.Traverse',
    'ephox.sugar.api.selection.Selection',
    'ephox.sugar.selection.core.NativeRange',
    'ephox.sugar.selection.core.SelectionDirection',
    'ephox.sugar.selection.query.CaretRange',
    'ephox.sugar.selection.query.Within',
    'ephox.sugar.selection.quirks.Prefilter'
  ],

  function (Option, DocumentPosition, Element, Fragment, Traverse, Selection, NativeRange, SelectionDirection, CaretRange, Within, Prefilter) {
    var doSetNativeRange = function (win, rng) {
      var selection = win.getSelection();
      selection.removeAllRanges();
      selection.addRange(rng);
    };

    var doSetRange = function (win, start, soffset, finish, foffset) {
      var rng = NativeRange.exactToNative(win, start, soffset, finish, foffset);
      doSetNativeRange(win, rng);
    };

    var findWithin = function (win, selection, selector) {
      return Within.find(win, selection, selector);
    };

    var setRangeFromRelative = function (win, relative) {
      return SelectionDirection.diagnose(win, relative).match({
        ltr: function (start, soffset, finish, foffset) {
          doSetRange(win, start, soffset, finish, foffset);
        },
        rtl: function (start, soffset, finish, foffset) {
          var selection = win.getSelection();
          // If this selection is backwards, then we need to use extend.
          if (selection.extend) {
            selection.collapse(start.dom(), soffset);
            selection.extend(finish.dom(), foffset);
          } else {
            doSetRange(win, finish, foffset, start, soffset);
          }
        }
      });
    };

    var setExact = function (win, start, soffset, finish, foffset) {
      var relative = Prefilter.preprocessExact(start, soffset, finish, foffset);

      setRangeFromRelative(win, relative);
    };

    var setRelative = function (win, startSitu, finishSitu) {
      var relative = Prefilter.preprocessRelative(startSitu, finishSitu);

      setRangeFromRelative(win, relative);
    };

    var toNative = function (selection) {
      var win = Selection.getWin(selection).dom();
      var getDomRange = function (start, soffset, finish, foffset) {
        return NativeRange.exactToNative(win, start, soffset, finish, foffset);
      };
      var filtered = Prefilter.preprocess(selection);
      return SelectionDirection.diagnose(win, filtered).match({
        ltr: getDomRange,
        rtl: getDomRange
      });
    };

    // NOTE: We are still reading the range because it gives subtly different behaviour
    // than using the anchorNode and focusNode. I'm not sure if this behaviour is any
    // better or worse; it's just different.
    var readRange = function (selection) {
      var rng = Option.from(selection.getRangeAt(0));
      return rng.map(function (r) {
        return Selection.range(Element.fromDom(r.startContainer), r.startOffset, Element.fromDom(r.endContainer), r.endOffset);
      });
    };

    var doGetExact = function (selection) {
      var anchorNode = Element.fromDom(selection.anchorNode);
      var focusNode = Element.fromDom(selection.focusNode);
      return DocumentPosition.after(anchorNode, selection.anchorOffset, focusNode, selection.focusOffset) ? Option.some(
        Selection.range(
          Element.fromDom(selection.anchorNode),
          selection.anchorOffset,
          Element.fromDom(selection.focusNode),
          selection.focusOffset
        )
      ) : readRange(selection);
    };

    var setToElement = function (win, element) {
      var rng = NativeRange.selectNodeContents(win, element);
      doSetNativeRange(win, rng);
    };

    var forElement = function (win, element) {
      var rng = NativeRange.selectNodeContents(win, element);
      return Selection.range(
        Element.fromDom(rng.startContainer), rng.startOffset,
        Element.fromDom(rng.endContainer), rng.endOffset
      );
    };

    var getExact = function (win) {
      // We want to retrieve the selection as it is.
      var selection = win.getSelection();
      return selection.rangeCount > 0 ? doGetExact(selection) : Option.none();
    };

    // TODO: Test this.
    var get = function (win) {
      return getExact(win).map(function (range) {
        return Selection.exact(range.start(), range.soffset(), range.finish(), range.foffset());
      });
    };

    var getFirstRect = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      return NativeRange.getFirstRect(rng);
    };

    var getBounds = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      return NativeRange.getBounds(rng);
    };

    var getAtPoint = function (win, x, y) {
      return CaretRange.fromPoint(win, x, y);
    };

    var getAsString = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      return NativeRange.toString(rng);
    };

    var clear = function (win) {
      var selection = win.getSelection();
      selection.removeAllRanges();
    };

    var clone = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      return NativeRange.cloneFragment(rng);
    };

    var replace = function (win, selection, elements) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      var fragment = Fragment.fromElements(elements);
      NativeRange.replaceWith(rng, fragment);
    };

    var deleteAt = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      NativeRange.deleteContents(rng);
    };

    return {
      setExact: setExact,
      getExact: getExact,
      get: get,
      setRelative: setRelative,
      toNative: toNative,
      setToElement: setToElement,
      clear: clear,

      clone: clone,
      replace: replace,
      deleteAt: deleteAt,

      forElement: forElement,

      getFirstRect: getFirstRect,
      getBounds: getBounds,
      getAtPoint: getAtPoint,

      findWithin: findWithin,
      getAsString: getAsString
    };
  }
);
<commit_msg>TBIO-5122 Changed readRange to match old WwwcModel behaviour<commit_after>define(
  'ephox.sugar.api.selection.WindowSelection',

  [
    'ephox.katamari.api.Option',
    'ephox.sugar.api.dom.DocumentPosition',
    'ephox.sugar.api.node.Element',
    'ephox.sugar.api.node.Fragment',
    'ephox.sugar.api.search.Traverse',
    'ephox.sugar.api.selection.Selection',
    'ephox.sugar.selection.core.NativeRange',
    'ephox.sugar.selection.core.SelectionDirection',
    'ephox.sugar.selection.query.CaretRange',
    'ephox.sugar.selection.query.Within',
    'ephox.sugar.selection.quirks.Prefilter'
  ],

  function (Option, DocumentPosition, Element, Fragment, Traverse, Selection, NativeRange, SelectionDirection, CaretRange, Within, Prefilter) {
    var doSetNativeRange = function (win, rng) {
      var selection = win.getSelection();
      selection.removeAllRanges();
      selection.addRange(rng);
    };

    var doSetRange = function (win, start, soffset, finish, foffset) {
      var rng = NativeRange.exactToNative(win, start, soffset, finish, foffset);
      doSetNativeRange(win, rng);
    };

    var findWithin = function (win, selection, selector) {
      return Within.find(win, selection, selector);
    };

    var setRangeFromRelative = function (win, relative) {
      return SelectionDirection.diagnose(win, relative).match({
        ltr: function (start, soffset, finish, foffset) {
          doSetRange(win, start, soffset, finish, foffset);
        },
        rtl: function (start, soffset, finish, foffset) {
          var selection = win.getSelection();
          // If this selection is backwards, then we need to use extend.
          if (selection.extend) {
            selection.collapse(start.dom(), soffset);
            selection.extend(finish.dom(), foffset);
          } else {
            doSetRange(win, finish, foffset, start, soffset);
          }
        }
      });
    };

    var setExact = function (win, start, soffset, finish, foffset) {
      var relative = Prefilter.preprocessExact(start, soffset, finish, foffset);

      setRangeFromRelative(win, relative);
    };

    var setRelative = function (win, startSitu, finishSitu) {
      var relative = Prefilter.preprocessRelative(startSitu, finishSitu);

      setRangeFromRelative(win, relative);
    };

    var toNative = function (selection) {
      var win = Selection.getWin(selection).dom();
      var getDomRange = function (start, soffset, finish, foffset) {
        return NativeRange.exactToNative(win, start, soffset, finish, foffset);
      };
      var filtered = Prefilter.preprocess(selection);
      return SelectionDirection.diagnose(win, filtered).match({
        ltr: getDomRange,
        rtl: getDomRange
      });
    };

    // NOTE: We are still reading the range because it gives subtly different behaviour
    // than using the anchorNode and focusNode. I'm not sure if this behaviour is any
    // better or worse; it's just different.
    var readRange = function (selection) {
      if (selection.rangeCount > 0) {
        var firstRng = selection.getRangeAt(0);
        var lastRng = selection.getRangeAt(selection.rangeCount - 1);

        return Option.some(Selection.range(
          Element.fromDom(firstRng.startContainer),
          firstRng.startOffset,
          Element.fromDom(lastRng.endContainer),
          lastRng.endOffset
        ));
      } else {
        return Option.none();
      }
    };

    var doGetExact = function (selection) {
      var anchorNode = Element.fromDom(selection.anchorNode);
      var focusNode = Element.fromDom(selection.focusNode);
      return DocumentPosition.after(anchorNode, selection.anchorOffset, focusNode, selection.focusOffset) ? Option.some(
        Selection.range(
          Element.fromDom(selection.anchorNode),
          selection.anchorOffset,
          Element.fromDom(selection.focusNode),
          selection.focusOffset
        )
      ) : readRange(selection);
    };

    var setToElement = function (win, element) {
      var rng = NativeRange.selectNodeContents(win, element);
      doSetNativeRange(win, rng);
    };

    var forElement = function (win, element) {
      var rng = NativeRange.selectNodeContents(win, element);
      return Selection.range(
        Element.fromDom(rng.startContainer), rng.startOffset,
        Element.fromDom(rng.endContainer), rng.endOffset
      );
    };

    var getExact = function (win) {
      // We want to retrieve the selection as it is.
      var selection = win.getSelection();
      return selection.rangeCount > 0 ? doGetExact(selection) : Option.none();
    };

    // TODO: Test this.
    var get = function (win) {
      return getExact(win).map(function (range) {
        return Selection.exact(range.start(), range.soffset(), range.finish(), range.foffset());
      });
    };

    var getFirstRect = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      return NativeRange.getFirstRect(rng);
    };

    var getBounds = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      return NativeRange.getBounds(rng);
    };

    var getAtPoint = function (win, x, y) {
      return CaretRange.fromPoint(win, x, y);
    };

    var getAsString = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      return NativeRange.toString(rng);
    };

    var clear = function (win) {
      var selection = win.getSelection();
      selection.removeAllRanges();
    };

    var clone = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      return NativeRange.cloneFragment(rng);
    };

    var replace = function (win, selection, elements) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      var fragment = Fragment.fromElements(elements);
      NativeRange.replaceWith(rng, fragment);
    };

    var deleteAt = function (win, selection) {
      var rng = SelectionDirection.asLtrRange(win, selection);
      NativeRange.deleteContents(rng);
    };

    return {
      setExact: setExact,
      getExact: getExact,
      get: get,
      setRelative: setRelative,
      toNative: toNative,
      setToElement: setToElement,
      clear: clear,

      clone: clone,
      replace: replace,
      deleteAt: deleteAt,

      forElement: forElement,

      getFirstRect: getFirstRect,
      getBounds: getBounds,
      getAtPoint: getAtPoint,

      findWithin: findWithin,
      getAsString: getAsString
    };
  }
);
<|endoftext|>


<commit_before>'use strict';

/*
 * Binds the attributes to the expression once at startup,
 * Usage:
 */

angular.module('fastBind.bindAttrOnce', []).
  directive('fastBindAttrOnce', ['$parse', function($parse) {
    return {
      compile: function compile(element, attributes) {
        var expr = $parse(attributes.fastBindOnce);

        return function link(scope, element) {
          var values = expr(scope);

          angular.forEach(values, function(value, key) {
            attrs.$set(key, value);
          });
        };
      }
    };
  }]);
<commit_msg>Fix use of attrs => attributes<commit_after>'use strict';

/*
 * Binds the attributes to the expression once at startup,
 * Usage:
 */

angular.module('fastBind.bindAttrOnce', []).
  directive('fastBindAttrOnce', ['$parse', function($parse) {
    return {
      compile: function compile(element, attributes) {
        var expr = $parse(attributes.fastBindOnce);

        return function link(scope, element) {
          var values = expr(scope);

          angular.forEach(values, function(value, key) {
            attributes.$set(key, value);
          });
        };
      }
    };
  }]);
<|endoftext|>