<commit_before>/**
 * @file TreeSelect component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import Dropdown from '../Dropdown';
import Tree from '../Tree';
import Theme from '../Theme';
import Tip from '../Tip';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';
import TreeCalculation from '../_vendors/TreeCalculation';
import SelectMode from '../_statics/SelectMode';

class TreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            value: props.value,
            popupVisible: false,
            path: props.selectMode === SelectMode.SINGLE_SELECT ?
                TreeCalculation.calPath(props.value, props.data, props) : undefined
        };

        this.closePopup = ::this.closePopup;
        this.getTriggerValue = ::this.getTriggerValue;
        this.nodeSelectHandler = ::this.nodeSelectHandler;
        this.changeHandler = ::this.changeHandler;
        this.popupClosedHandler = ::this.popupClosedHandler;

    }

    closePopup() {
        this.refs.dropdown.closePopup();
    }

    getTriggerValue(props = this.props) {

        const {data, selectMode, placeholder, triggerRenderer, renderer, displayField, valueField} = props,
            {value, path} = this.state,

            isMultiSelect = selectMode === SelectMode.MULTI_SELECT;

        if (!value) {
            return placeholder;
        }

        if (triggerRenderer) {
            return triggerRenderer(value, path);
        }

        if (isMultiSelect) {
            return value.length > 0 ?
                value.length + ' selected'
                :
                placeholder;
        }

        let result = [];

        function addNode(node, i) {
            result.push(
                renderer ?

                        {renderer(node, path && path.slice(0, i + 1))}

                    :
                    Util.getTextByDisplayField(node, displayField, valueField)
            );
        }

        addNode(data, -1);

        if (path) {
            for (let i = 0, len = path.length; i < len; i++) {

                result.push(

                );

                addNode(path[i].node, i);

            }
        }

        return result;

    }

    nodeSelectHandler(value, path) {

        if (this.props.selectMode !== SelectMode.SINGLE_SELECT) {
            return;
        }

        this.setState({
            path
        });

    }

    changeHandler(value) {

        const {autoClose} = this.props;
        if (autoClose) {
            this.closePopup();
        }

        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });

    }

    popupClosedHandler(e) {
        this.setState({
            popupVisible: false
        }, () => {
            const {onClosePopup} = this.props;
            onClosePopup && onClosePopup(e);
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.props.value) {
            this.setState({
                value: nextProps.value
            });
        }
    }

    render() {

        const {

                className, popupClassName, style, name, popupTheme, data, renderer,
                selectMode, valueField, displayField, descriptionField,
                onItemTouchTap, popupChildren,

                ...restProps

            } = this.props,
            {value, popupVisible} = this.state,

            wrapperClassName = classNames('tree-select', {
                [className]: className
            }),

            triggerClassName = classNames({
                activated: popupVisible,
                empty: !value
            }),
            selectPopupClassName = classNames('tree-select-popup', {
                [popupClassName]: popupClassName
            }),

            triggerValue = this.getTriggerValue();

        return (

                {
                    name ?
                        <input type="hidden"
                               name={name}
                               value={Util.getValueByValueField(value, valueField, displayField)}/>
                        :
                        null
                }

                <Dropdown {...restProps}
                          ref="dropdown"
                          triggerClassName={triggerClassName}
                          popupClassName={selectPopupClassName}
                          popupTheme={popupTheme}
                          triggerValue={triggerValue}
                          onClosePopup={this.popupClosedHandler}>

 {
                             Event.wheelHandler(e, this.props);
                         }}>

                        <Tree className="tree-select-list"
                              theme={popupTheme}
                              selectMode={selectMode}
                              data={data}
                              value={value}
                              valueField={valueField}
                              displayField={displayField}
                              descriptionField={descriptionField}
                              renderer={renderer}
                              onItemTouchTap={onItemTouchTap}
                              onNodeSelect={this.nodeSelectHandler}
                              onChange={this.changeHandler}/>

                    {popupChildren}

                </Dropdown>

        );

    }
};

TreeSelect.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The theme.
     */
    popupTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The name of the dropDownSelect.
     */
    name: PropTypes.string,

    /**
     * The value of the dropDownSelect.
     */
    value: PropTypes.any,

    /**
     * The placeholder of the dropDownSelect.
     */
    placeholder: PropTypes.string,

    rightIconCls: PropTypes.string,

    /**
     * The options data.
     */
    data: PropTypes.shape({

        /**
         * The CSS class name of the tree node.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the tree node.
         */
        style: PropTypes.object,

        /**
         * The theme of the tree button.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The text value of the tree button.Type can be string or number.
         */
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The tree node's display text. Type can be string, number or bool.
         */
        text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The desc value of the tree node. Type can be string or number.
         */
        desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * If true,the tree node will be disabled.
         */
        disabled: PropTypes.bool,

        /**
         * If true,the button will be have loading effect.
         */
        isLoading: PropTypes.bool,

        /**
         * Use this property to display an icon. It will display on the left.
         */
        iconCls: PropTypes.string,

        /**
         * Use this property to display an icon. It will display on the right.
         */
        rightIconCls: PropTypes.string,

        /**
         * The message of tip.
         */
        tip: PropTypes.string,

        /**
         * The position of tip.
         */
        tipPosition: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

        children: PropTypes.array,

        /**
         * You can create a complicated renderer callback instead of value and desc prop.
         */
        itemRenderer: PropTypes.func,

        /**
         * Callback function fired when a tree node touch-tapped.
         */
        onTouchTap: PropTypes.func

    }),

    /**
     * The invalid message of dropDownSelect.
     */
    invalidMsg: PropTypes.string,

    /**
     * If true,the dropDownSelect will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * The select mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * The message of the dropDownSelect.
     */
    infoMsg: PropTypes.string,

    /**
     * Use this function to format the options's text.
     */
    textFormat: PropTypes.func,

    /**
     * If true,the drop-down box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    shouldPreventContainerScroll: PropTypes.bool,

    popupChildren: PropTypes.any,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.func,

    /**
     * Callback function fired when the button is touch-tapped.
     */
    onItemTouchTap: PropTypes.func,

    /**
     * Callback function fired when the popup is closed.
     */
    onClosePopup: PropTypes.func,

    /**
     * Callback function fired when a menu item is selected.
     */
    onChange: PropTypes.func,

    onWheel: PropTypes.func,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onTriggerMouseOver: PropTypes.func,
    onTriggerMouseOut: PropTypes.func

};

TreeSelect.defaultProps = {

    className: null,
    popupClassName: null,
    style: null,
    popupStyle: null,
    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    name: null,
    value: null,
    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    data: null,
    invalidMsg: null,
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,

    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',

    infoMsg: null,
    autoClose: true,

    shouldPreventContainerScroll: true,

    popupChildren: null

};

export default TreeSelect;<commit_msg>update TreeSelect<commit_after>/**
 * @file TreeSelect component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import Dropdown from '../Dropdown';
import Tree from '../Tree';
import Theme from '../Theme';
import Tip from '../Tip';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';
import TreeCalculation from '../_vendors/TreeCalculation';
import SelectMode from '../_statics/SelectMode';

class TreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            value: props.value,
            popupVisible: false,
            path: props.selectMode === SelectMode.SINGLE_SELECT ?
                TreeCalculation.calPath(props.value, props.data, props) : undefined
        };

        this.closePopup = ::this.closePopup;
        this.getTriggerValue = ::this.getTriggerValue;
        this.nodeSelectHandler = ::this.nodeSelectHandler;
        this.changeHandler = ::this.changeHandler;
        this.popupClosedHandler = ::this.popupClosedHandler;

    }

    closePopup() {
        this.refs.dropdown.closePopup();
    }

    getTriggerValue(props = this.props) {

        const {data, selectMode, placeholder, triggerRenderer, renderer, displayField, valueField} = props,
            {value, path} = this.state,

            isMultiSelect = selectMode === SelectMode.MULTI_SELECT;

        if (!value) {
            return placeholder;
        }

        if (triggerRenderer) {
            return triggerRenderer(value, path);
        }

        if (isMultiSelect) {
            return value.length > 0 ?
                value.length + ' selected'
                :
                placeholder;
        }

        let result = [];

        function addNode(node, i) {
            result.push(
                renderer ?

                        {renderer(node, path && path.slice(0, i + 1))}

                    :
                    Util.getTextByDisplayField(node, displayField, valueField)
            );
        }

        addNode(data, -1);

        if (path) {
            for (let i = 0, len = path.length; i < len; i++) {

                result.push(

                );

                addNode(path[i].node, i);

            }
        }

        return result;

    }

    nodeSelectHandler(value, path) {

        if (this.props.selectMode !== SelectMode.SINGLE_SELECT) {
            return;
        }

        this.setState({
            path
        });

    }

    changeHandler(value) {

        const {autoClose} = this.props;
        if (autoClose) {
            this.closePopup();
        }

        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });

    }

    popupClosedHandler(e) {
        this.setState({
            popupVisible: false
        }, () => {
            const {onClosePopup} = this.props;
            onClosePopup && onClosePopup(e);
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.props.value) {
            this.setState({
                value: nextProps.value
            });
        }
    }

    render() {

        const {

                className, popupClassName, style, name, popupTheme, data, renderer,
                selectMode, valueField, displayField, descriptionField,
                onItemTouchTap, popupChildren,

                ...restProps

            } = this.props,
            {value, popupVisible} = this.state,

            wrapperClassName = classNames('tree-select', {
                [className]: className
            }),

            triggerClassName = classNames({
                activated: popupVisible,
                empty: !value
            }),
            selectPopupClassName = classNames('tree-select-popup', {
                [popupClassName]: popupClassName
            }),

            triggerValue = this.getTriggerValue();

        return (

                {
                    name ?
                        <input type="hidden"
                               name={name}
                               value={Util.getValueByValueField(value, valueField, displayField)}/>
                        :
                        null
                }

                <Dropdown {...restProps}
                          ref="dropdown"
                          triggerClassName={triggerClassName}
                          popupClassName={selectPopupClassName}
                          popupTheme={popupTheme}
                          triggerValue={triggerValue}
                          onClosePopup={this.popupClosedHandler}>

 {
                             Event.wheelHandler(e, this.props);
                         }}>

                        <Tree className="tree-select-list"
                              theme={popupTheme}
                              selectMode={selectMode}
                              data={data}
                              value={value}
                              valueField={valueField}
                              displayField={displayField}
                              descriptionField={descriptionField}
                              renderer={renderer}
                              onItemTouchTap={onItemTouchTap}
                              onNodeSelect={this.nodeSelectHandler}
                              onChange={this.changeHandler}/>

                    {popupChildren}

                </Dropdown>

        );

    }
};

TreeSelect.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The theme.
     */
    popupTheme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * The name of the dropDownSelect.
     */
    name: PropTypes.string,

    /**
     * The value of the dropDownSelect.
     */
    value: PropTypes.any,

    /**
     * The placeholder of the dropDownSelect.
     */
    placeholder: PropTypes.string,

    rightIconCls: PropTypes.string,

    /**
     * The options data.
     */
    data: PropTypes.shape({

        /**
         * The CSS class name of the tree node.
         */
        className: PropTypes.string,

        /**
         * Override the styles of the tree node.
         */
        style: PropTypes.object,

        /**
         * The theme of the tree button.
         */
        theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

        /**
         * The text value of the tree button.Type can be string or number.
         */
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The tree node's display text. Type can be string, number or bool.
         */
        text: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * The desc value of the tree node. Type can be string or number.
         */
        desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

        /**
         * If true,the tree node will be disabled.
         */
        disabled: PropTypes.bool,

        /**
         * If true,the button will be have loading effect.
         */
        isLoading: PropTypes.bool,

        /**
         * Use this property to display an icon. It will display on the left.
         */
        iconCls: PropTypes.string,

        /**
         * Use this property to display an icon. It will display on the right.
         */
        rightIconCls: PropTypes.string,

        /**
         * The message of tip.
         */
        tip: PropTypes.string,

        /**
         * The position of tip.
         */
        tipPosition: PropTypes.oneOf(Util.enumerateValue(Tip.Position)),

        children: PropTypes.array,

        /**
         * You can create a complicated renderer callback instead of value and desc prop.
         */
        itemRenderer: PropTypes.func,

        /**
         * Callback function fired when a tree node touch-tapped.
         */
        onTouchTap: PropTypes.func

    }),

    /**
     * The invalid message of dropDownSelect.
     */
    invalidMsg: PropTypes.string,

    /**
     * If true,the dropDownSelect will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * The select mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * The message of the dropDownSelect.
     */
    infoMsg: PropTypes.string,

    /**
     * Use this function to format the options's text.
     */
    textFormat: PropTypes.func,

    /**
     * If true,the drop-down box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    shouldPreventContainerScroll: PropTypes.bool,

    popupChildren: PropTypes.any,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.func,

    /**
     * Callback function fired when the button is touch-tapped.
     */
    onItemTouchTap: PropTypes.func,

    /**
     * Callback function fired when the popup is closed.
     */
    onClosePopup: PropTypes.func,

    /**
     * Callback function fired when a menu item is selected.
     */
    onChange: PropTypes.func,

    onWheel: PropTypes.func,
    onFocus: PropTypes.func,
    onBlur: PropTypes.func,
    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func

};

TreeSelect.defaultProps = {

    className: null,
    popupClassName: null,
    style: null,
    popupStyle: null,
    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    name: null,
    value: null,
    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    data: null,
    invalidMsg: null,
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,

    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',

    infoMsg: null,
    autoClose: true,

    shouldPreventContainerScroll: true,

    popupChildren: null

};

export default TreeSelect;<|endoftext|>


<commit_before>mwUI.Backbone.Filter = function () {
  // If it is an invalid value return null otherwise the provided object
  var returnNullOrObjectFor = function (value, object) {
    return (_.isUndefined(value) || value === null || value === '' || value.length===0 || (_.isArray(value) && _.compact(value).length===0)) ? null : object;
  };

  var returnNullOrObjectForMultipleValues = function (values, object) {
    var hasValue = false;
    if(!_.isObject(values)){
      console.log(values);
      throw new Error('The argument values has to be an object');
    }
    for(var key in values){
      if(returnNullOrObjectFor(values[key], true)){
        hasValue = true;
      } else {
        delete object[key];
      }
    }
    return hasValue ? object : null;
  };

  return {
    containsString: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'containsString',
        fieldName: fieldName,
        contains: value
      });
    },

    string: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'string',
        fieldName: fieldName,
        value: value
      });
    },

    and: function (filters) {
      return this.logOp(filters, 'AND');
    },

    nand: function (filters) {
      return this.logOp(filters, 'NAND');
    },

    or: function (filters) {
      return this.logOp(filters, 'OR');
    },

    logOp: function (filters, operator) {
      filters = _.without(filters, null); // Removing null values from existing filters

      return filters.length === 0 ? null : { // Ignore logOps with empty filters
        type: 'logOp',
        operation: operator,
        filters: filters
      };
    },

    boolean: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'boolean',
        fieldName: fieldName,
        value: value
      });
    },

    stringMap: function (fieldName, key, value) {
      if(value === '%%'){
        value = '';
      }
      return returnNullOrObjectFor(value, {
        type: 'stringMap',
        fieldName: fieldName,
        value: value,
        key: key
      });
    },

    stringEnum: function (fieldName, values) {
      return returnNullOrObjectFor(values, {
        type: 'stringEnum',
        fieldName: fieldName,
        values: _.flatten(values)
      });
    },

    long: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'long',
        fieldName: fieldName,
        value: value
      });
    },

    like: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'like',
        fieldName: fieldName,
        like: value
      });
    },

    notNull: function (fieldName) {
      return returnNullOrObjectFor(true, {
        type: 'null',
        fieldName: fieldName
      });
    },

    dateRange: function(fieldName, min, max){
      return returnNullOrObjectForMultipleValues({min: min, max: max}, {
        type: 'dateRange',
        fieldName: fieldName,
        min: min,
        max: max
      });
    },

    longRange: function(fieldName, min, max){
      return returnNullOrObjectForMultipleValues({min: min, max: max}, {
        type: 'longRange',
        fieldName: fieldName,
        min: min,
        max: max
      });
    }
  };

};
<commit_msg>convert value to a timestamp when a value exists<commit_after>mwUI.Backbone.Filter = function () {
  // If it is an invalid value return null otherwise the provided object
  var returnNullOrObjectFor = function (value, object) {
    return (_.isUndefined(value) || value === null || value === '' || value.length===0 || (_.isArray(value) && _.compact(value).length===0)) ? null : object;
  };

  var returnNullOrObjectForMultipleValues = function (values, object) {
    var hasValue = false;
    if(!_.isObject(values)){
      console.log(values);
      throw new Error('The argument values has to be an object');
    }
    for(var key in values){
      if(returnNullOrObjectFor(values[key], true)){
        hasValue = true;
      } else {
        delete object[key];
      }
    }
    return hasValue ? object : null;
  };

  return {
    containsString: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'containsString',
        fieldName: fieldName,
        contains: value
      });
    },

    string: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'string',
        fieldName: fieldName,
        value: value
      });
    },

    and: function (filters) {
      return this.logOp(filters, 'AND');
    },

    nand: function (filters) {
      return this.logOp(filters, 'NAND');
    },

    or: function (filters) {
      return this.logOp(filters, 'OR');
    },

    logOp: function (filters, operator) {
      filters = _.without(filters, null); // Removing null values from existing filters

      return filters.length === 0 ? null : { // Ignore logOps with empty filters
        type: 'logOp',
        operation: operator,
        filters: filters
      };
    },

    boolean: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'boolean',
        fieldName: fieldName,
        value: value
      });
    },

    stringMap: function (fieldName, key, value) {
      if(value === '%%'){
        value = '';
      }
      return returnNullOrObjectFor(value, {
        type: 'stringMap',
        fieldName: fieldName,
        value: value,
        key: key
      });
    },

    stringEnum: function (fieldName, values) {
      return returnNullOrObjectFor(values, {
        type: 'stringEnum',
        fieldName: fieldName,
        values: _.flatten(values)
      });
    },

    long: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'long',
        fieldName: fieldName,
        value: value
      });
    },

    like: function (fieldName, value) {
      return returnNullOrObjectFor(value, {
        type: 'like',
        fieldName: fieldName,
        like: value
      });
    },

    notNull: function (fieldName) {
      return returnNullOrObjectFor(true, {
        type: 'null',
        fieldName: fieldName
      });
    },

    dateRange: function(fieldName, min, max){
      min = min ? +new Date(min) : null;
      max = max ? +new Date(max) : null;
      return returnNullOrObjectForMultipleValues({min: min, max: max}, {
        type: 'dateRange',
        fieldName: fieldName,
        min: min,
        max: max
      });
    },

    longRange: function(fieldName, min, max){
      return returnNullOrObjectForMultipleValues({min: min, max: max}, {
        type: 'longRange',
        fieldName: fieldName,
        min: min,
        max: max
      });
    }
  };

};
<|endoftext|>


<commit_before>/*
 * Copyright 2008 Google Inc.
 *
 * 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.
 */

/**
 * @fileoverview Definitions for Gecko's custom CSS properties. Copied from:
 * http://lxr.mozilla.org/mozilla1.8.0/source/dom/public/idl/css/nsIDOMCSS2Properties.idl
 *
 * @externs
 * @author nicksantos@google.com (Nick Santos)
 */

/** @type {string} */ CSSProperties.prototype.MozAppearance;
/** @type {string} */ CSSProperties.prototype.MozBackgroundClip;
/** @type {string} */ CSSProperties.prototype.MozBackgroundInlinePolicy;
/** @type {string} */ CSSProperties.prototype.MozBackgroundOrigin;
/** @type {string} */ CSSProperties.prototype.MozBinding;
/** @type {string} */ CSSProperties.prototype.MozBorderBottomColors;
/** @type {string} */ CSSProperties.prototype.MozBorderLeftColors;
/** @type {string} */ CSSProperties.prototype.MozBorderRightColors;
/** @type {string} */ CSSProperties.prototype.MozBorderTopColors;
/** @type {string} */ CSSProperties.prototype.MozBorderRadius;
/** @type {string} */ CSSProperties.prototype.MozBorderRadiusTopleft;
/** @type {string} */ CSSProperties.prototype.MozBorderRadiusTopright;
/** @type {string} */ CSSProperties.prototype.MozBorderRadiusBottomleft;
/** @type {string} */ CSSProperties.prototype.MozBorderRadiusBottomright;
/** @type {string} */ CSSProperties.prototype.MozBoxAlign;
/** @type {string} */ CSSProperties.prototype.MozBoxDirection;
/** @type {string} */ CSSProperties.prototype.MozBoxFlex;
/** @type {string} */ CSSProperties.prototype.MozBoxOrient;
/** @type {string} */ CSSProperties.prototype.MozBoxOrdinalGroup;
/** @type {string} */ CSSProperties.prototype.MozBoxPack;
/** @type {string} */ CSSProperties.prototype.MozBoxSizing;
/** @type {string} */ CSSProperties.prototype.MozColumnCount;
/** @type {string} */ CSSProperties.prototype.MozColumnWidth;
/** @type {string} */ CSSProperties.prototype.MozColumnGap;
/** @type {string} */ CSSProperties.prototype.MozFloatEdge;
/** @type {string} */ CSSProperties.prototype.MozForceBrokenImageIcon;
/** @type {string} */ CSSProperties.prototype.MozImageRegion;
/** @type {string} */ CSSProperties.prototype.MozMarginEnd;
/** @type {string} */ CSSProperties.prototype.MozMarginStart;
/** @type {string|number} */ CSSProperties.prototype.MozOpacity;
/** @type {string} */ CSSProperties.prototype.MozOutline;
/** @type {string} */ CSSProperties.prototype.MozOutlineColor;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadius;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadiusTopleft;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadiusTopright;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadiusBottomleft;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadiusBottomright;
/** @type {string} */ CSSProperties.prototype.MozOutlineStyle;
/** @type {string} */ CSSProperties.prototype.MozOutlineWidth;
/** @type {string} */ CSSProperties.prototype.MozOutlineOffset;
/** @type {string} */ CSSProperties.prototype.MozPaddingEnd;
/** @type {string} */ CSSProperties.prototype.MozPaddingStart;
/** @type {string} */ CSSProperties.prototype.MozUserFocus;
/** @type {string} */ CSSProperties.prototype.MozUserInput;
/** @type {string} */ CSSProperties.prototype.MozUserModify;
/** @type {string} */ CSSProperties.prototype.MozUserSelect;
<commit_msg><commit_after>/*
 * Copyright 2008 Google Inc.
 *
 * 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.
 */

/**
 * @fileoverview Definitions for Gecko's custom CSS properties. Copied from:
 * http://mxr.mozilla.org/mozilla2.0/source/dom/interfaces/css/nsIDOMCSS2Properties.idl
 *
 * @externs
 * @author nicksantos@google.com (Nick Santos)
 */

/** @type {string} */ CSSProperties.prototype.MozAppearance;
/** @type {string} */ CSSProperties.prototype.MozBackgroundClip;
/** @type {string} */ CSSProperties.prototype.MozBackgroundInlinePolicy;
/** @type {string} */ CSSProperties.prototype.MozBackgroundOrigin;
/** @type {string} */ CSSProperties.prototype.MozBinding;
/** @type {string} */ CSSProperties.prototype.MozBorderBottomColors;
/** @type {string} */ CSSProperties.prototype.MozBorderEnd;
/** @type {string} */ CSSProperties.prototype.MozBorderEndColor;
/** @type {string} */ CSSProperties.prototype.MozBorderEndStyle;
/** @type {string} */ CSSProperties.prototype.MozBorderEndWidth;
/** @type {string} */ CSSProperties.prototype.MozBorderImage;
/** @type {string} */ CSSProperties.prototype.MozBorderLeftColors;
/** @type {string} */ CSSProperties.prototype.MozBorderRadius;
/** @type {string} */ CSSProperties.prototype.MozBorderRadiusTopleft;
/** @type {string} */ CSSProperties.prototype.MozBorderRadiusTopright;
/** @type {string} */ CSSProperties.prototype.MozBorderRadiusBottomleft;
/** @type {string} */ CSSProperties.prototype.MozBorderRadiusBottomright;
/** @type {string} */ CSSProperties.prototype.MozBorderRightColors;
/** @type {string} */ CSSProperties.prototype.MozBorderStart;
/** @type {string} */ CSSProperties.prototype.MozBorderStartColor;
/** @type {string} */ CSSProperties.prototype.MozBorderStartStyle;
/** @type {string} */ CSSProperties.prototype.MozBorderStartWidth;
/** @type {string} */ CSSProperties.prototype.MozBorderTopColors;
/** @type {string} */ CSSProperties.prototype.MozBoxAlign;
/** @type {string} */ CSSProperties.prototype.MozBoxDirection;
/** @type {string} */ CSSProperties.prototype.MozBoxFlex;
/** @type {string} */ CSSProperties.prototype.MozBoxOrdinalGroup;
/** @type {string} */ CSSProperties.prototype.MozBoxOrient;
/** @type {string} */ CSSProperties.prototype.MozBoxPack;
/** @type {string} */ CSSProperties.prototype.MozBoxSizing;
/** @type {string} */ CSSProperties.prototype.MozColumnCount;
/** @type {string} */ CSSProperties.prototype.MozColumnGap;
/** @type {string} */ CSSProperties.prototype.MozColumnRule;
/** @type {string} */ CSSProperties.prototype.MozColumnRuleColor;
/** @type {string} */ CSSProperties.prototype.MozColumnRuleStyle;
/** @type {string} */ CSSProperties.prototype.MozColumnRuleWidth;
/** @type {string} */ CSSProperties.prototype.MozColumnWidth;
/** @type {string} */ CSSProperties.prototype.MozFloatEdge;
/** @type {string} */ CSSProperties.prototype.MozFontFeatureSettings;
/** @type {string} */ CSSProperties.prototype.MozFontLanguageOverride;
/** @type {string} */ CSSProperties.prototype.MozForceBrokenImageIcon;
/** @type {string} */ CSSProperties.prototype.MozImageRegion;
/** @type {string} */ CSSProperties.prototype.MozMarginEnd;
/** @type {string} */ CSSProperties.prototype.MozMarginStart;
/** @type {number|string} */ CSSProperties.prototype.MozOpacity;
/** @type {string} */ CSSProperties.prototype.MozOutline;
/** @type {string} */ CSSProperties.prototype.MozOutlineColor;
/** @type {string} */ CSSProperties.prototype.MozOutlineOffset;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadius;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadiusBottomleft;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadiusBottomright;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadiusTopleft;
/** @type {string} */ CSSProperties.prototype.MozOutlineRadiusTopright;
/** @type {string} */ CSSProperties.prototype.MozOutlineStyle;
/** @type {string} */ CSSProperties.prototype.MozOutlineWidth;
/** @type {string} */ CSSProperties.prototype.MozPaddingEnd;
/** @type {string} */ CSSProperties.prototype.MozPaddingStart;
/** @type {string} */ CSSProperties.prototype.MozStackSizing;
/** @type {string} */ CSSProperties.prototype.MozTabSize;
/** @type {string} */ CSSProperties.prototype.MozTransform;
/** @type {string} */ CSSProperties.prototype.MozTransformOrigin;
/** @type {string} */ CSSProperties.prototype.MozTransition;
/** @type {string} */ CSSProperties.prototype.MozTransitionDelay;
/** @type {string} */ CSSProperties.prototype.MozTransitionDuration;
/** @type {string} */ CSSProperties.prototype.MozTransitionProperty;
/** @type {string} */ CSSProperties.prototype.MozTransitionTimingFunction;
/** @type {string} */ CSSProperties.prototype.MozUserFocus;
/** @type {string} */ CSSProperties.prototype.MozUserInput;
/** @type {string} */ CSSProperties.prototype.MozUserModify;
/** @type {string} */ CSSProperties.prototype.MozUserSelect;
/** @type {string} */ CSSProperties.prototype.MozWindowShadow;
<|endoftext|>


<commit_before>/*
 * Copyright 2008 Google Inc.
 *
 * 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.
 */

/**
 * @fileoverview Definitions for W3C's event specification.
 *  The whole file has been fully type annotated.
 *  Created from
 *   http://www.w3.org/TR/DOM-Level-2-Events/ecma-script-binding.html
 *
 * @externs
 */

/**
 * @interface
 */
function EventTarget() {}

/**
 * @param {string} type
 * @param {EventListener|function(Event):(boolean|undefined)} listener
 * @param {boolean} useCapture
 * @return {undefined}
 */
EventTarget.prototype.addEventListener = function(type, listener, useCapture) {};

/**
 * @param {string} type
 * @param {EventListener|function(Event):(boolean|undefined)} listener
 * @param {boolean} useCapture
 * @return {undefined}
 */
EventTarget.prototype.removeEventListener = function(type, listener, useCapture) {};

/**
 * @param {Event} evt
 * @return {boolean}
 */
EventTarget.prototype.dispatchEvent = function(evt) {};

/**
 * @constructor
 */
function EventListener() {}

/**
 * @param {Event} evt
 * @return {undefined}
 */
EventListener.prototype.handleEvent = function(evt) {};

/**
 * @constructor
 */
function Event() {}

/**
 * @type {number}
 * @see http://www.w3.org/TR/DOM-Level-2-Events/ecma-script-binding.html
 */
Event.AT_TARGET;

/**
 * @type {number}
 * @see http://www.w3.org/TR/DOM-Level-2-Events/ecma-script-binding.html
 */
Event.BUBBLING_PHASE;

/**
 * @type {number}
 * @see http://www.w3.org/TR/DOM-Level-2-Events/ecma-script-binding.html
 */
Event.CAPTURING_PHASE;

/** @type {string} */
Event.prototype.type;

/** @type {EventTarget} */
Event.prototype.target;

/** @type {EventTarget} */
Event.prototype.currentTarget;

/** @type {number} */
Event.prototype.eventPhase;

/** @type {boolean} */
Event.prototype.bubbles;

/** @type {boolean} */
Event.prototype.cancelable;

/** @type {number} */
Event.prototype.timeStamp;

/** @type {Object} */
Event.prototype.state;

/**
 * @return {undefined}
 */
Event.prototype.stopPropagation = function() {};

/**
 * @return {undefined}
 */
Event.prototype.preventDefault = function() {};

/**
 * @param {string} eventTypeArg
 * @param {boolean} canBubbleArg
 * @param {boolean} cancelableArg
 * @return {undefined}
 */
Event.prototype.initEvent = function(eventTypeArg, canBubbleArg, cancelableArg) {};

/**
 * @constructor
 * @extends {Event}
 * @see http://www.w3.org/TR/DOM-Level-3-Events/#interface-CustomEvent
 */
function CustomEvent() {}

/**
 * @param {string} eventType
 * @param {boolean} bubbles
 * @param {boolean} cancelable
 * @param {*} detail
 */
CustomEvent.prototype.initCustomEvent = function(
    eventType, bubbles, cancelable, detail) {};

/**
 * @type {*}
 */
CustomEvent.prototype.detail;

/**
 * @constructor
 */
function DocumentEvent() {}

/**
 * @param {string} eventType
 * @return {Event}
 */
DocumentEvent.prototype.createEvent = function(eventType) {};

/**
 * @constructor
 * @extends {Event}
 */
function UIEvent() {}

/** @type {number} */
UIEvent.prototype.detail;

///**
// * @param {string} typeArg
// * @param {boolean} canBubbleArg
// * @param {boolean} cancelableArg
// * @param {AbstractView} viewArg
// * @param {number} detailArg
// * @return undefined
// */
//UIEvent.prototype.initUIEvent = function (typeArg, canBubbleArg, cancelableArg, viewArg, detailArg) {};

/**
 * @constructor
 * @extends {UIEvent}
 */
function MouseEvent() {}

/** @type {number} */
MouseEvent.prototype.screenX;

/** @type {number} */
MouseEvent.prototype.screenY;

/** @type {number} */
MouseEvent.prototype.clientX;

/** @type {number} */
MouseEvent.prototype.clientY;

/** @type {boolean} */
MouseEvent.prototype.ctrlKey;

/** @type {boolean} */
MouseEvent.prototype.shiftKey;

/** @type {boolean} */
MouseEvent.prototype.altKey;

/** @type {boolean} */
MouseEvent.prototype.metaKey;

/** @type {number} */
MouseEvent.prototype.button;

/** @type {EventTarget} */
MouseEvent.prototype.relatedTarget;

/**
 * @constructor
 * @extends {Event}
 */
function MutationEvent() {}

/** @type {Node} */
MutationEvent.prototype.relatedNode;

/** @type {string} */
MutationEvent.prototype.prevValue;

/** @type {string} */
MutationEvent.prototype.newValue;

/** @type {string} */
MutationEvent.prototype.attrName;

/** @type {number} */
MutationEvent.prototype.attrChange;

/**
 * @param {string} typeArg
 * @param {boolean} canBubbleArg
 * @param {boolean} cancelableArg
 * @param {Node} relatedNodeArg
 * @param {string} prevValueArg
 * @param {string} newValueArg
 * @param {string} attrNameArg
 * @param {number} attrChangeArg
 * @return {undefined}
 */
MutationEvent.prototype.initMutationEvent = function(typeArg, canBubbleArg, cancelableArg, relatedNodeArg, prevValueArg, newValueArg, attrNameArg, attrChangeArg) {};

// DOM3
/**
 * @constructor
 * @extends {UIEvent}
 */
function KeyboardEvent() {}

/** @type {string} */
KeyboardEvent.prototype.keyIdentifier;

/** @type {boolean} */
KeyboardEvent.prototype.ctrlKey;

/** @type {boolean} */
KeyboardEvent.prototype.shiftKey;

/** @type {boolean} */
KeyboardEvent.prototype.altKey;

/** @type {boolean} */
KeyboardEvent.prototype.metaKey;

/**
 * @param {string} keyIdentifierArg
 * @return {boolean}
 */
KeyboardEvent.prototype.getModifierState = function(keyIdentifierArg) {};
<commit_msg><commit_after>/*
 * Copyright 2008 Google Inc.
 *
 * 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.
 */

/**
 * @fileoverview Definitions for W3C's event specification.
 *  The whole file has been fully type annotated.
 *  Created from
 *   http://www.w3.org/TR/DOM-Level-2-Events/ecma-script-binding.html
 *
 * @externs
 */

/**
 * @interface
 */
function EventTarget() {}

/**
 * @param {string} type
 * @param {EventListener|function(Event):(boolean|undefined)} listener
 * @param {boolean} useCapture
 * @return {undefined}
 */
EventTarget.prototype.addEventListener = function(type, listener, useCapture) {};

/**
 * @param {string} type
 * @param {EventListener|function(Event):(boolean|undefined)} listener
 * @param {boolean} useCapture
 * @return {undefined}
 */
EventTarget.prototype.removeEventListener = function(type, listener, useCapture) {};

/**
 * @param {Event} evt
 * @return {boolean}
 */
EventTarget.prototype.dispatchEvent = function(evt) {};

/**
 * @interface
 */
function EventListener() {}

/**
 * @param {Event} evt
 * @return {undefined}
 */
EventListener.prototype.handleEvent = function(evt) {};

/**
 * @constructor
 */
function Event() {}

/**
 * @type {number}
 * @see http://www.w3.org/TR/DOM-Level-2-Events/ecma-script-binding.html
 */
Event.AT_TARGET;

/**
 * @type {number}
 * @see http://www.w3.org/TR/DOM-Level-2-Events/ecma-script-binding.html
 */
Event.BUBBLING_PHASE;

/**
 * @type {number}
 * @see http://www.w3.org/TR/DOM-Level-2-Events/ecma-script-binding.html
 */
Event.CAPTURING_PHASE;

/** @type {string} */
Event.prototype.type;

/** @type {EventTarget} */
Event.prototype.target;

/** @type {EventTarget} */
Event.prototype.currentTarget;

/** @type {number} */
Event.prototype.eventPhase;

/** @type {boolean} */
Event.prototype.bubbles;

/** @type {boolean} */
Event.prototype.cancelable;

/** @type {number} */
Event.prototype.timeStamp;

/** @type {Object} */
Event.prototype.state;

/**
 * @return {undefined}
 */
Event.prototype.stopPropagation = function() {};

/**
 * @return {undefined}
 */
Event.prototype.preventDefault = function() {};

/**
 * @param {string} eventTypeArg
 * @param {boolean} canBubbleArg
 * @param {boolean} cancelableArg
 * @return {undefined}
 */
Event.prototype.initEvent = function(eventTypeArg, canBubbleArg, cancelableArg) {};

/**
 * @constructor
 * @extends {Event}
 * @see http://www.w3.org/TR/DOM-Level-3-Events/#interface-CustomEvent
 */
function CustomEvent() {}

/**
 * @param {string} eventType
 * @param {boolean} bubbles
 * @param {boolean} cancelable
 * @param {*} detail
 */
CustomEvent.prototype.initCustomEvent = function(
    eventType, bubbles, cancelable, detail) {};

/**
 * @type {*}
 */
CustomEvent.prototype.detail;

/**
 * @constructor
 */
function DocumentEvent() {}

/**
 * @param {string} eventType
 * @return {Event}
 */
DocumentEvent.prototype.createEvent = function(eventType) {};

/**
 * @constructor
 * @extends {Event}
 */
function UIEvent() {}

/** @type {number} */
UIEvent.prototype.detail;

///**
// * @param {string} typeArg
// * @param {boolean} canBubbleArg
// * @param {boolean} cancelableArg
// * @param {AbstractView} viewArg
// * @param {number} detailArg
// * @return undefined
// */
//UIEvent.prototype.initUIEvent = function (typeArg, canBubbleArg, cancelableArg, viewArg, detailArg) {};

/**
 * @constructor
 * @extends {UIEvent}
 */
function MouseEvent() {}

/** @type {number} */
MouseEvent.prototype.screenX;

/** @type {number} */
MouseEvent.prototype.screenY;

/** @type {number} */
MouseEvent.prototype.clientX;

/** @type {number} */
MouseEvent.prototype.clientY;

/** @type {boolean} */
MouseEvent.prototype.ctrlKey;

/** @type {boolean} */
MouseEvent.prototype.shiftKey;

/** @type {boolean} */
MouseEvent.prototype.altKey;

/** @type {boolean} */
MouseEvent.prototype.metaKey;

/** @type {number} */
MouseEvent.prototype.button;

/** @type {EventTarget} */
MouseEvent.prototype.relatedTarget;

/**
 * @constructor
 * @extends {Event}
 */
function MutationEvent() {}

/** @type {Node} */
MutationEvent.prototype.relatedNode;

/** @type {string} */
MutationEvent.prototype.prevValue;

/** @type {string} */
MutationEvent.prototype.newValue;

/** @type {string} */
MutationEvent.prototype.attrName;

/** @type {number} */
MutationEvent.prototype.attrChange;

/**
 * @param {string} typeArg
 * @param {boolean} canBubbleArg
 * @param {boolean} cancelableArg
 * @param {Node} relatedNodeArg
 * @param {string} prevValueArg
 * @param {string} newValueArg
 * @param {string} attrNameArg
 * @param {number} attrChangeArg
 * @return {undefined}
 */
MutationEvent.prototype.initMutationEvent = function(typeArg, canBubbleArg, cancelableArg, relatedNodeArg, prevValueArg, newValueArg, attrNameArg, attrChangeArg) {};

// DOM3
/**
 * @constructor
 * @extends {UIEvent}
 */
function KeyboardEvent() {}

/** @type {string} */
KeyboardEvent.prototype.keyIdentifier;

/** @type {boolean} */
KeyboardEvent.prototype.ctrlKey;

/** @type {boolean} */
KeyboardEvent.prototype.shiftKey;

/** @type {boolean} */
KeyboardEvent.prototype.altKey;

/** @type {boolean} */
KeyboardEvent.prototype.metaKey;

/**
 * @param {string} keyIdentifierArg
 * @return {boolean}
 */
KeyboardEvent.prototype.getModifierState = function(keyIdentifierArg) {};
<|endoftext|>


<commit_before>/* global YT */
angular.module('youtube-embed', [])
.service ('youtubeEmbedUtils', ['$window', '$rootScope', function ($window, $rootScope) {
    var Service = {}

    // adapted from http://stackoverflow.com/a/5831191/1614967
    var youtubeRegexp = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube(?:-nocookie)?\.com\S*[^\w\s-])([\w-]{11})(?=[^\w-]|$)(?![?=&+%\w.-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig;
    var timeRegexp = /t=(\d+)[ms]?(\d+)?s?/;

    function contains(str, substr) {
        return (str.indexOf(substr) > -1);
    }

    Service.getIdFromURL = function getIdFromURL(url) {
        var id = url.replace(youtubeRegexp, '$1');

        if (contains(id, ';')) {
            var pieces = id.split(';');

            if (contains(pieces[1], '%')) {
                // links like this:
                // "http://www.youtube.com/attribution_link?a=pxa6goHqzaA&u=%2Fwatch%3Fv%3DdPdgx30w9sU%26feature%3Dshare"
                // have the real query string URI encoded behind a ';'.
                // at this point, `id is 'pxa6goHqzaA;u=%2Fwatch%3Fv%3DdPdgx30w9sU%26feature%3Dshare'
                var uriComponent = decodeURIComponent(id.split(';')[1]);
                id = ('http://youtube.com' + uriComponent)
                        .replace(youtubeRegexp, '$1');
            } else {
                // https://www.youtube.com/watch?v=VbNF9X1waSc&feature=youtu.be
                // `id` looks like 'VbNF9X1waSc;feature=youtu.be' currently.
                // strip the ';feature=youtu.be'
                id = pieces[0];
            }
        } else if (contains(id, '#')) {
            // id might look like '93LvTKF_jW0#t=1'
            // and we want '93LvTKF_jW0'
            id = id.split('#')[0];
        }

        return id;
    };

    Service.getTimeFromURL = function getTimeFromURL(url) {
        url = url || '';

        // t=4m20s
        // returns ['t=4m20s', '4', '20']
        // t=46s
        // returns ['t=46s', '46']
        // t=46
        // returns ['t=46', '46']
        var times = url.match(timeRegexp);

        if (!times) {
            // zero seconds
            return 0;
        }

        // assume the first
        var full = times[0],
            minutes = times[1],
            seconds = times[2];

        // t=4m20s
        if (typeof seconds !== 'undefined') {
            seconds = parseInt(seconds, 10);
            minutes = parseInt(minutes, 10);

        // t=4m
        } else if (contains(full, 'm')) {
            minutes = parseInt(minutes, 10);
            seconds = 0;

        // t=4s
        // t=4
        } else {
            seconds = parseInt(minutes, 10);
            minutes = 0;
        }

        // in seconds
        return seconds + (minutes * 60);
    };

    // Inject YouTube's iFrame API
    (function () {
        var tag = document.createElement('script');
        tag.src = '//www.youtube.com/iframe_api';
        var firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
    }());

    Service.ready = false;

    // Youtube callback when API is ready
    $window.onYouTubeIframeAPIReady = function () {
        $rootScope.$apply(function () {
            Service.ready = true;
        });
    };

    return Service
}])
.directive('youtubeVideo', ['youtubeEmbedUtils', function (youtubeEmbedUtils) {
    var uniqId = 1;

    // from YT.PlayerState
    var stateNames = {
        '-1': 'unstarted',
        0: 'ended',
        1: 'playing',
        2: 'paused',
        3: 'buffering',
        5: 'queued'
    };

    var eventPrefix = 'youtube.player.';

    return {
        restrict: 'EA',
        scope: {
            videoId: '=?',
            videoUrl: '=?',
            player: '=?',
            playerVars: '=?',
            playerHeight: '=?',
            playerWidth: '=?',
        },
        link: function (scope, element, attrs) {
            // allows us to $watch `ready`
            scope.utils = youtubeEmbedUtils;

            // player-id attr > id attr > directive-generated ID
            var playerId = attrs.playerId || element[0].id || 'unique-youtube-embed-id-' + uniqId++;
            element[0].id = playerId;

            // Attach to element
            scope.playerHeight = scope.playerHeight || 390;
            scope.playerWidth = scope.playerWidth || 640;
            if (!scope.playerVars) scope.playerVars = {};

            // YT calls callbacks outside of digest cycle
            function applyBroadcast () {
                var args = Array.prototype.slice.call(arguments);
                scope.$apply(function () {
                    scope.$emit.apply(scope, args);
                });
            }

            function onPlayerStateChange (event) {
                var state = stateNames[event.data];
                if (typeof state !== 'undefined') {
                    applyBroadcast(eventPrefix + state, scope.player, event);
                }
                scope.player.currentState = state;
            }

            function onPlayerReady (event) {
                if (scope.start) {
                    // scope.player.seekTo(parseInt(scope.start, 10), true);
                }

                applyBroadcast(eventPrefix + 'ready', scope.player, event);
            }

            function createPlayer () {
                var player = new YT.Player(playerId, {
                    height: scope.playerHeight,
                    width: scope.playerWidth,
                    videoId: scope.videoId,
                    playerVars: scope.playerVars,
                    events: {
                        onReady: onPlayerReady,
                        onStateChange: onPlayerStateChange
                    }
                });

                player.id = playerId;
                return player;
            }

            function loadPlayer () {
                if (playerId && scope.videoId) {
                    if (scope.player && typeof scope.player.destroy === 'function') {
                        scope.player.destroy();
                    }

                    scope.player = createPlayer();
                }
            };

            var stopWatchingReady = scope.$watch(
                function () {
                    return scope.utils.ready
                        // Wait until one of them is defined...
                        && (typeof scope.videoUrl !== 'undefined'
                        ||  typeof scope.videoId !== 'undefined');
                },
                function (ready) {
                    if (ready) {
                        stopWatchingReady();

                        // use URL if you've got it
                        if (typeof scope.videoUrl !== 'undefined') {
                            scope.$watch('videoUrl', function (url) {
                                scope.videoId = scope.utils.getIdFromURL(url);

                                var start = scope.utils.getTimeFromURL(url);
                                scope.playerVars.start = scope.playerVars.start || start;

                                loadPlayer();
                            });

                        // otherwise, watch the id
                        } else {
                            scope.$watch('videoId', function (id) {
                                scope.videoId = id;
                                loadPlayer();
                            });
                        }
                    }
            });
        }
    };
}]);
<commit_msg>some clean up, $apply changes to currentState<commit_after>/* global YT */
angular.module('youtube-embed', ['ng'])
.service ('youtubeEmbedUtils', ['$window', '$rootScope', function ($window, $rootScope) {
    var Service = {}

    // adapted from http://stackoverflow.com/a/5831191/1614967
    var youtubeRegexp = /https?:\/\/(?:[0-9A-Z-]+\.)?(?:youtu\.be\/|youtube(?:-nocookie)?\.com\S*[^\w\s-])([\w-]{11})(?=[^\w-]|$)(?![?=&+%\w.-]*(?:['"][^<>]*>|<\/a>))[?=&+%\w.-]*/ig;
    var timeRegexp = /t=(\d+)[ms]?(\d+)?s?/;

    function contains(str, substr) {
        return (str.indexOf(substr) > -1);
    }

    Service.getIdFromURL = function getIdFromURL(url) {
        var id = url.replace(youtubeRegexp, '$1');

        if (contains(id, ';')) {
            var pieces = id.split(';');

            if (contains(pieces[1], '%')) {
                // links like this:
                // "http://www.youtube.com/attribution_link?a=pxa6goHqzaA&u=%2Fwatch%3Fv%3DdPdgx30w9sU%26feature%3Dshare"
                // have the real query string URI encoded behind a ';'.
                // at this point, `id is 'pxa6goHqzaA;u=%2Fwatch%3Fv%3DdPdgx30w9sU%26feature%3Dshare'
                var uriComponent = decodeURIComponent(id.split(';')[1]);
                id = ('http://youtube.com' + uriComponent)
                        .replace(youtubeRegexp, '$1');
            } else {
                // https://www.youtube.com/watch?v=VbNF9X1waSc&feature=youtu.be
                // `id` looks like 'VbNF9X1waSc;feature=youtu.be' currently.
                // strip the ';feature=youtu.be'
                id = pieces[0];
            }
        } else if (contains(id, '#')) {
            // id might look like '93LvTKF_jW0#t=1'
            // and we want '93LvTKF_jW0'
            id = id.split('#')[0];
        }

        return id;
    };

    Service.getTimeFromURL = function getTimeFromURL(url) {
        url = url || '';

        // t=4m20s
        // returns ['t=4m20s', '4', '20']
        // t=46s
        // returns ['t=46s', '46']
        // t=46
        // returns ['t=46', '46']
        var times = url.match(timeRegexp);

        if (!times) {
            // zero seconds
            return 0;
        }

        // assume the first
        var full = times[0],
            minutes = times[1],
            seconds = times[2];

        // t=4m20s
        if (typeof seconds !== 'undefined') {
            seconds = parseInt(seconds, 10);
            minutes = parseInt(minutes, 10);

        // t=4m
        } else if (contains(full, 'm')) {
            minutes = parseInt(minutes, 10);
            seconds = 0;

        // t=4s
        // t=4
        } else {
            seconds = parseInt(minutes, 10);
            minutes = 0;
        }

        // in seconds
        return seconds + (minutes * 60);
    };

    // Inject YouTube's iFrame API
    (function () {
        var tag = document.createElement('script');
        tag.src = '//www.youtube.com/iframe_api';
        var firstScriptTag = document.getElementsByTagName('script')[0];
        firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
    }());

    Service.ready = false;

    // Youtube callback when API is ready
    $window.onYouTubeIframeAPIReady = function () {
        $rootScope.$apply(function () {
            Service.ready = true;
        });
    };

    return Service;
}])
.directive('youtubeVideo', ['youtubeEmbedUtils', function (youtubeEmbedUtils) {
    var uniqId = 1;

    // from YT.PlayerState
    var stateNames = {
        '-1': 'unstarted',
        0: 'ended',
        1: 'playing',
        2: 'paused',
        3: 'buffering',
        5: 'queued'
    };

    var eventPrefix = 'youtube.player.';

    return {
        restrict: 'EA',
        scope: {
            videoId: '=?',
            videoUrl: '=?',
            player: '=?',
            playerVars: '=?',
            playerHeight: '=?',
            playerWidth: '=?'
        },
        link: function (scope, element, attrs) {
            // allows us to $watch `ready`
            scope.utils = youtubeEmbedUtils;

            // player-id attr > id attr > directive-generated ID
            var playerId = attrs.playerId || element[0].id || 'unique-youtube-embed-id-' + uniqId++;
            element[0].id = playerId;

            // Attach to element
            scope.playerHeight = scope.playerHeight || 390;
            scope.playerWidth = scope.playerWidth || 640;
            scope.playerVars = scope.playerVars || {};

            // YT calls callbacks outside of digest cycle
            function applyBroadcast () {
                var args = Array.prototype.slice.call(arguments);
                scope.$apply(function () {
                    scope.$emit.apply(scope, args);
                });
            }

            function onPlayerStateChange (event) {
                var state = stateNames[event.data];
                if (typeof state !== 'undefined') {
                    applyBroadcast(eventPrefix + state, scope.player, event);
                }
                scope.$apply(function () {
                    scope.player.currentState = state;
                });
            }

            function onPlayerReady (event) {
                applyBroadcast(eventPrefix + 'ready', scope.player, event);
            }

            function createPlayer () {
                var player = new YT.Player(playerId, {
                    height: scope.playerHeight,
                    width: scope.playerWidth,
                    videoId: scope.videoId,
                    playerVars: scope.playerVars,
                    events: {
                        onReady: onPlayerReady,
                        onStateChange: onPlayerStateChange
                    }
                });

                player.id = playerId;
                return player;
            }

            function loadPlayer () {
                if (playerId && scope.videoId) {
                    if (scope.player && typeof scope.player.destroy === 'function') {
                        scope.player.destroy();
                    }

                    scope.player = createPlayer();
                }
            };

            var stopWatchingReady = scope.$watch(
                function () {
                    return scope.utils.ready
                        // Wait until one of them is defined...
                        && (typeof scope.videoUrl !== 'undefined'
                        ||  typeof scope.videoId !== 'undefined');
                },
                function (ready) {
                    if (ready) {
                        stopWatchingReady();

                        // use URL if you've got it
                        if (typeof scope.videoUrl !== 'undefined') {
                            scope.$watch('videoUrl', function (url) {
                                scope.videoId = scope.utils.getIdFromURL(url);

                                var start = scope.utils.getTimeFromURL(url);
                                scope.playerVars.start = scope.playerVars.start || start;

                                loadPlayer();
                            });

                        // otherwise, watch the id
                        } else {
                            scope.$watch('videoId', function (id) {
                                loadPlayer();
                            });
                        }
                    }
            });
        }
    };
}]);
<|endoftext|>


<commit_before>#!/usr/bin/env node

var exec = require('child_process').exec;
var fs = require( 'fs' );
var exclude = require('./excludeterm.js').exclusion;
var nano = require('nano')('http://localhost:5984');
nano.db.create('respondent');
nano.db.create('appellant');
var resp = nano.db.use('respondent');
var appe = nano.db.use('appellant');
nano.db.create('docStats');
var docStats = nano.db.use('docStats');

fs.readdir('/vagrant/import', function( err, files ) {
  processFile(files);
});
/*exec('/vagrant/extraction/split.sh /vagrant/to100txt/to100txt/*.txt', function(error, stdout, stderr) {

});*/

function processFile(files) {
  file = files.pop();
  if(file.indexOf('.json') > -1) {
    console.log(file);
    exec('/vagrant/extraction/sideDec.js '+file, function(error,side,stderr) {
      console.log(side);
      exec('/vagrant/extraction/split.sh /vagrant/import/'+file.replace('json','txt'), function(error, stdout, stderr) {
        if(fs.existsSync('/vagrant/import/'+file.replace('.json','_summary.txt')) && fs.existsSync('/vagrant/import/'+file.replace('.json','_conclusion.txt'))) {
          exec('/vagrant/extraction/positiveNegative.js '+file.replace('.json','_conclusion.txt'), function (error, outcome, error) {
            if(outcome.indexOf('unknow') > -1) {
              processFile(files);
              return;
            }
            else {
              if(outcome.indexOf('negative') > -1) {
                outcome = 'negative';
              } else {
                outcome = 'positive';
              }
            }
            console.log(outcome);
            exec('/opt/apache-opennlp-1.8.0/bin/opennlp SentenceDetector /vagrant/models/en-sent.bin < /vagrant/import/'+file.replace('.json','_summary.txt')+' | /opt/apache-opennlp-1.8.0/bin/opennlp TokenizerME /vagrant/models/en-token.bin | /opt/apache-opennlp-1.8.0/bin/opennlp POSTagger /vagrant/models/en-pos-maxent.bin | /opt/apache-opennlp-1.8.0/bin/opennlp ChunkerME /vagrant/models/en-chunker.bin', function(error, stdout, stderr) {
              var rawTerms = stdout.match(new RegExp('\\[[^\\]]+\\]', 'g'))
              var terms = [];
              for(i in rawTerms) {
                var valid = true;
                for(j in exclude) {
                  rawTerms[i] = rawTerms[i].replace(new RegExp('\\s[^\\s]+'+exclude[j],'g'), '');
                }
                if(rawTerms[i].indexOf('_') > -1) {
                  terms.push(rawTerms[i]);
                }
              }
              terms = Array.from(new Set(terms));
              if(side.indexOf('respondent') > -1) {
                for(i in terms) {
                  resp.get(terms[i], function(err, body){
                    var w = 0;
                    var l = 0;
                    if(!err) {
                      w = body.wins;
                      l = body.losses;
                    }
                    if(outcome.indexOf('positive')) {
                      w = w+1;
                    } else {
                      l = l+1;
                    }
                    resp.insert({_id: terms[i], wins: w, losses: l}, function(err, body){});
                  });
                }
              } else {
                for(i in terms) {
                  resp.get(terms[i], function(err, body){
                    var w = 0;
                    var l = 0;
                    if(!err) {
                      w = body.wins;
                      l = body.losses;
                    }
                    if(outcome.indexOf('positive')) {
                      w = w+1;
                    } else {
                      l = l+1;
                    }
                    resp.insert({_id: terms[i], wins: w, losses: l}, function(err, body){});
                  });
                }
              }
              docStats.get('docStat', function(err, body) {
                var w = 0;
                var l = 0;
                if(!err) {
                  w = body.wins;
                  l = body.losses;
                }
                if(outcome.indexOf('positive')) {
                  w = w+1;
                } else {
                  l = l+1;
                }
                docStats.insert({_id: 'docStat', wins: w, losses: l}, function(err, body){});
                processFile(files);
              });
            });
          });
        }
      });
    });
  /*
  */
} else processFile(files);

}
<commit_msg>added missing process<commit_after>#!/usr/bin/env node

var exec = require('child_process').exec;
var fs = require( 'fs' );
var exclude = require('./excludeterm.js').exclusion;
var nano = require('nano')('http://localhost:5984');
nano.db.create('respondent');
nano.db.create('appellant');
var resp = nano.db.use('respondent');
var appe = nano.db.use('appellant');
nano.db.create('docStats');
var docStats = nano.db.use('docStats');

fs.readdir('/vagrant/import', function( err, files ) {
  processFile(files);
});
/*exec('/vagrant/extraction/split.sh /vagrant/to100txt/to100txt/*.txt', function(error, stdout, stderr) {

});*/

function processFile(files) {
  file = files.pop();
  if(file.indexOf('.json') > -1) {
    console.log(file);
    exec('/vagrant/extraction/sideDec.js '+file, function(error,side,stderr) {
      console.log(side);
      exec('/vagrant/extraction/split.sh /vagrant/import/'+file.replace('json','txt'), function(error, stdout, stderr) {
        if(fs.existsSync('/vagrant/import/'+file.replace('.json','_summary.txt')) && fs.existsSync('/vagrant/import/'+file.replace('.json','_conclusion.txt'))) {
          exec('/vagrant/extraction/positiveNegative.js '+file.replace('.json','_conclusion.txt'), function (error, outcome, error) {
            if(outcome.indexOf('unknow') > -1) {
              processFile(files);
              return;
            }
            else {
              if(outcome.indexOf('negative') > -1) {
                outcome = 'negative';
              } else {
                outcome = 'positive';
              }
            }
            console.log(outcome);
            exec('/opt/apache-opennlp-1.8.0/bin/opennlp SentenceDetector /vagrant/models/en-sent.bin < /vagrant/import/'+file.replace('.json','_summary.txt')+' | /opt/apache-opennlp-1.8.0/bin/opennlp TokenizerME /vagrant/models/en-token.bin | /opt/apache-opennlp-1.8.0/bin/opennlp POSTagger /vagrant/models/en-pos-maxent.bin | /opt/apache-opennlp-1.8.0/bin/opennlp ChunkerME /vagrant/models/en-chunker.bin', function(error, stdout, stderr) {
              var rawTerms = stdout.match(new RegExp('\\[[^\\]]+\\]', 'g'))
              var terms = [];
              for(i in rawTerms) {
                var valid = true;
                for(j in exclude) {
                  rawTerms[i] = rawTerms[i].replace(new RegExp('\\s[^\\s]+'+exclude[j],'g'), '');
                }
                if(rawTerms[i].indexOf('_') > -1) {
                  terms.push(rawTerms[i]);
                }
              }
              terms = Array.from(new Set(terms));
              if(side.indexOf('respondent') > -1) {
                for(i in terms) {
                  resp.get(terms[i], function(err, body){
                    var w = 0;
                    var l = 0;
                    if(!err) {
                      w = body.wins;
                      l = body.losses;
                    }
                    if(outcome.indexOf('positive')) {
                      w = w+1;
                    } else {
                      l = l+1;
                    }
                    resp.insert({_id: terms[i], wins: w, losses: l}, function(err, body){});
                  });
                }
              } else {
                for(i in terms) {
                  resp.get(terms[i], function(err, body){
                    var w = 0;
                    var l = 0;
                    if(!err) {
                      w = body.wins;
                      l = body.losses;
                    }
                    if(outcome.indexOf('positive')) {
                      w = w+1;
                    } else {
                      l = l+1;
                    }
                    resp.insert({_id: terms[i], wins: w, losses: l}, function(err, body){});
                  });
                }
              }
              docStats.get('docStat', function(err, body) {
                var w = 0;
                var l = 0;
                if(!err) {
                  w = body.wins;
                  l = body.losses;
                }
                if(outcome.indexOf('positive')) {
                  w = w+1;
                } else {
                  l = l+1;
                }
                docStats.insert({_id: 'docStat', wins: w, losses: l}, function(err, body){});
                processFile(files);
              });
            });
          });
        } else processFile(files);
      });
    });
  /*
  */
} else processFile(files);

}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

'use strict';

// Meter class that generates a number correlated to audio volume.
// The meter class itself displays nothing, but it makes the
// instantaneous and time-decaying volumes available for inspection.
// It also reports on the fraction of samples that were at or near
// the top of the measurement range.
function SoundMeter(context) {
  this.context = context;
  this.instant = 0.0;
  this.slow = 0.0;
  this.clip = 0.0;
  this.url = "/sendmessage/{0}/{1}";

  $("#btnStart").click(function() {

    var phone = $("#phoneNumber").val()
    if(phone == "" || !phone.contains("+1")) {
      $("#phoneNumber").parents(".form-group").removeClass("has-error").addClass("has-error");
      alert("Input a valid phone number, with country code +1.");
    } else {
      $("#phoneNumber").parents(".form-group").removeClass("has-error");
      $("#phoneNumber").prop('disabled', true);
      $("#threshold").prop('disabled', true);
      $(this).remove();
      tracking=true;
    }
  });

  // The audio sample session object
  this.session = {
    ticksOverThreshold: 0,
    threshold: false,
    cumulativeVolume: new Array(),
    outputTimePeriods: new Array(),
    messageStatus: false,
    sampledData: new Array(),
    thisOutputTimePeriod: 0.0
  }

  this.script = context.createScriptProcessor(2048, 1, 1);

  // Use the reduce function's method signature to get the sum of an array's values
  this.getSum = function(previousValue, currentValue, index, array) {
    return previousValue + currentValue;
  };

  // This method returns true when the current session's cumulative volume output
  // is one of the top 3 highest outputs since the observation began
  this.getMessageStatus = function(that, save) {
    var sendMessage = false;
    var outputTimePeriod = 0.0;
    // Get cumulative volume
    outputTimePeriod = that.session.cumulativeVolume.reduce(that.getSum);
    // If the output time period is in the top 3
    if(that.session.outputTimePeriods.length < 3) {
      sendMessage = true;
      that.session.thisOutputTimePeriod = outputTimePeriod;
      if(save)
        that.session.outputTimePeriods.push(outputTimePeriod);
    } else {
      // Sort the array ascending
      that.session.outputTimePeriods.sort();
      // Replace the value at index 0 if current outputTimePeriod is a greater value
      if(that.session.outputTimePeriods[0] < outputTimePeriod) {
        sendMessage = true;
        that.session.thisOutputTimePeriod = outputTimePeriod;
        if(save)
          that.session.outputTimePeriods[0] = outputTimePeriod;
      }
    }

    return sendMessage;
  };

  // This method returns true if the output volume has exceeded the
  // threshold for at least 1 second and the session's output is
  // in the top 3 highest outputs since the observation began
  this.updateMessageStatus = function(that) {
    // Send message flag
    var notifyUser = false;

    // Record the last second of the output volume if the state has changed
    if(that.session.threshold == false)
      that.session.cumulativeVolume.push(that.slow);

    // Update the threshold state
    that.session.threshold = true;
    that.session.sampledData.push(that.instant);
    // 20 ticks is about 1 second
    if(that.session.ticksOverThreshold >= 20){
      // Capture the cumulative volume output over the time period
      that.session.cumulativeVolume.push(that.slow);
      // Reset the sample counter
      that.session.ticksOverThreshold = 0;
      // Check notification status
      notifyUser = that.getMessageStatus(that, false);
    } else {
      // Increment the sample counter (~50ms per tick)
      that.session.ticksOverThreshold += 1;
    }

    return notifyUser;
  };

  // Shhhhhhh...
  this.sendMessage = function(that) {
    $("#chart-container").trigger("noiseAlert", [that.session.sampledData, that.session.thisOutputTimePeriod]);

    $.ajax({
      url: that.url.replace("{0}", $("#phoneNumber").val()).replace("{1}", "Noise Alert: " + that.session.thisOutputTimePeriod),
      type: 'get',
      headers: {
          "Content-Type": "application/json; charset=utf-8"
      },
      dataType: 'json',
      success: function (data) {
          console.info(data);
      }
    });
};

  var that = this;

  this.script.onaudioprocess = function(event) {
    if(tracking == true) {
    var input = event.inputBuffer.getChannelData(0);
    var i;
    var sum = 0.0;
    for (i = 0; i < input.length; ++i) {
      sum += input[i] * input[i];
    }

    // The average volume for the last 50ms
    that.instant = Math.sqrt(sum / input.length);

    // The average volume for the last 1s
    that.slow = 0.95 * that.slow + 0.05 * that.instant;

    // The average volume for the last 1s has exceeded the minimum threshold
    if(that.slow > parseFloat($("#threshold").val())) {
      // Update the message status
      var notifyUser = that.updateMessageStatus(that);

      // Only notify the user once per session
      if(!that.session.messageStatus ? notifyUser : false) {
        // Update the session's message status
        that.session.messageStatus = true;
        // Send the message notification
        that.sendMessage(that);
      }
    } else {
      if(that.session.threshold) {
        // Save the session's output
        that.getMessageStatus(that, true);
        // Reset session state
        that.session.threshold = false;
        that.session.cumulativeVolume = new Array();
        that.session.sampledData = new Array();
        that.session.ticksOverThreshold = 0;
        that.session.messageStatus = false;
      }
    }
  }
  };
}

SoundMeter.prototype.connectToSource = function(stream) {
  console.log('SoundMeter connecting');
  this.mic = this.context.createMediaStreamSource(stream);
  this.mic.connect(this.script);
  // necessary to make sample run, but should not be.
  this.script.connect(this.context.destination);
};

SoundMeter.prototype.stop = function() {
  this.mic.disconnect();
  this.script.disconnect();
};
<commit_msg>JS fix<commit_after>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

'use strict';

// Meter class that generates a number correlated to audio volume.
// The meter class itself displays nothing, but it makes the
// instantaneous and time-decaying volumes available for inspection.
// It also reports on the fraction of samples that were at or near
// the top of the measurement range.
function SoundMeter(context) {
  this.context = context;
  this.instant = 0.0;
  this.slow = 0.0;
  this.clip = 0.0;
  this.url = "/sendmessage/{0}/{1}";

  $("#btnStart").click(function() {

    var phone = $("#phoneNumber").val();
    if(phone == "" || !phone.contains("+1")) {
      $("#phoneNumber").parents(".form-group").removeClass("has-error").addClass("has-error");
      alert("Input a valid phone number, with country code +1.");
    } else {
      $("#phoneNumber").parents(".form-group").removeClass("has-error");
      $("#phoneNumber").prop('disabled', true);
      $("#threshold").prop('disabled', true);
      $(this).remove();
      tracking=true;
    }
  });

  // The audio sample session object
  this.session = {
    ticksOverThreshold: 0,
    threshold: false,
    cumulativeVolume: new Array(),
    outputTimePeriods: new Array(),
    messageStatus: false,
    sampledData: new Array(),
    thisOutputTimePeriod: 0.0
  }

  this.script = context.createScriptProcessor(2048, 1, 1);

  // Use the reduce function's method signature to get the sum of an array's values
  this.getSum = function(previousValue, currentValue, index, array) {
    return previousValue + currentValue;
  };

  // This method returns true when the current session's cumulative volume output
  // is one of the top 3 highest outputs since the observation began
  this.getMessageStatus = function(that, save) {
    var sendMessage = false;
    var outputTimePeriod = 0.0;
    // Get cumulative volume
    outputTimePeriod = that.session.cumulativeVolume.reduce(that.getSum);
    // If the output time period is in the top 3
    if(that.session.outputTimePeriods.length < 3) {
      sendMessage = true;
      that.session.thisOutputTimePeriod = outputTimePeriod;
      if(save)
        that.session.outputTimePeriods.push(outputTimePeriod);
    } else {
      // Sort the array ascending
      that.session.outputTimePeriods.sort();
      // Replace the value at index 0 if current outputTimePeriod is a greater value
      if(that.session.outputTimePeriods[0] < outputTimePeriod) {
        sendMessage = true;
        that.session.thisOutputTimePeriod = outputTimePeriod;
        if(save)
          that.session.outputTimePeriods[0] = outputTimePeriod;
      }
    }

    return sendMessage;
  };

  // This method returns true if the output volume has exceeded the
  // threshold for at least 1 second and the session's output is
  // in the top 3 highest outputs since the observation began
  this.updateMessageStatus = function(that) {
    // Send message flag
    var notifyUser = false;

    // Record the last second of the output volume if the state has changed
    if(that.session.threshold == false)
      that.session.cumulativeVolume.push(that.slow);

    // Update the threshold state
    that.session.threshold = true;
    that.session.sampledData.push(that.instant);
    // 20 ticks is about 1 second
    if(that.session.ticksOverThreshold >= 20){
      // Capture the cumulative volume output over the time period
      that.session.cumulativeVolume.push(that.slow);
      // Reset the sample counter
      that.session.ticksOverThreshold = 0;
      // Check notification status
      notifyUser = that.getMessageStatus(that, false);
    } else {
      // Increment the sample counter (~50ms per tick)
      that.session.ticksOverThreshold += 1;
    }

    return notifyUser;
  };

  // Shhhhhhh...
  this.sendMessage = function(that) {
    $("#chart-container").trigger("noiseAlert", [that.session.sampledData, that.session.thisOutputTimePeriod]);

    $.ajax({
      url: that.url.replace("{0}", $("#phoneNumber").val()).replace("{1}", "Noise Alert: " + that.session.thisOutputTimePeriod),
      type: 'get',
      headers: {
          "Content-Type": "application/json; charset=utf-8"
      },
      dataType: 'json',
      success: function (data) {
          console.info(data);
      }
    });
};

  var that = this;

  this.script.onaudioprocess = function(event) {
    if(tracking == true) {
    var input = event.inputBuffer.getChannelData(0);
    var i;
    var sum = 0.0;
    for (i = 0; i < input.length; ++i) {
      sum += input[i] * input[i];
    }

    // The average volume for the last 50ms
    that.instant = Math.sqrt(sum / input.length);

    // The average volume for the last 1s
    that.slow = 0.95 * that.slow + 0.05 * that.instant;

    // The average volume for the last 1s has exceeded the minimum threshold
    if(that.slow > parseFloat($("#threshold").val())) {
      // Update the message status
      var notifyUser = that.updateMessageStatus(that);

      // Only notify the user once per session
      if(!that.session.messageStatus ? notifyUser : false) {
        // Update the session's message status
        that.session.messageStatus = true;
        // Send the message notification
        that.sendMessage(that);
      }
    } else {
      if(that.session.threshold) {
        // Save the session's output
        that.getMessageStatus(that, true);
        // Reset session state
        that.session.threshold = false;
        that.session.cumulativeVolume = new Array();
        that.session.sampledData = new Array();
        that.session.ticksOverThreshold = 0;
        that.session.messageStatus = false;
      }
    }
  }
  };
}

SoundMeter.prototype.connectToSource = function(stream) {
  console.log('SoundMeter connecting');
  this.mic = this.context.createMediaStreamSource(stream);
  this.mic.connect(this.script);
  // necessary to make sample run, but should not be.
  this.script.connect(this.context.destination);
};

SoundMeter.prototype.stop = function() {
  this.mic.disconnect();
  this.script.disconnect();
};
<|endoftext|>