<commit_before>/**
 * @file 一个树形选择控件。
 * @author Han Bing Feng (hanbingfeng@baidu.com)
 */

define(function (require) {
    let _ = require('underscore');
    let React = require('react');
    let util = require('./core/util.es6');

    /**
     * 一个树节点的定义
     */
    let treeNodeType = React.PropTypes.shape({
        /**
         * 树节点id
         */
        id: React.PropTypes.string,
        /**
         * 树节点文本内容
         */
        name: React.PropTypes.string,
        /**
         * 树节点的 载入中 状态
         */
        isChildrenLoading: React.PropTypes.bool,
        /**
         * 树节点的 已载入 状态
         */
        isChildrenLoaded: React.PropTypes.bool,
        /**
         * 所有孩子
         */
        children: React.PropTypes.arrayOf(treeNodeType)
    });

    let TreeNode = React.createClass({
        propTypes: {
            /**
             * 树节点
             */
            treeNode: treeNodeType,
            /**
             * 树名字过滤器，不包含过滤器中字符串的节点将加上class`fcui2-tree-node-filtered`。
             */
            nameFilter: React.PropTypes.string,
            /**
             * 树节点是否被展开。
             */
            isExpanded: React.PropTypes.bool,
            /**
             * 树节点展开按钮被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeExpandClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeExpandClicked.treeNode 被展开的树节点数据
             */
            onTreeNodeExpandClicked: React.PropTypes.func,
            /**
             * 树节点“操作”按钮被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeOperationClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeOperationClicked.treeNode 被操作的树节点数据
             */
            onTreeNodeOperationClicked: React.PropTypes.func,
            /**
             * 树节点其他位置被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeClicked.treeNode 被操作的树节点数据
             */
            onTreeNodeClicked: React.PropTypes.func,
            /**
             * 树节点载入中时的话术提示。
             * @type {[type]}
             */
            textLoading: React.PropTypes.string,
            /**
             * 树节点根节点附加的class。
             */
            className: React.PropTypes.string
        },

        getDefaultProps() {
            return {
                onTreeNodeExpandClicked: _.noop,
                onTreeNodeOperationClicked: _.noop,
                onTreeNodeClicked: _.noop
            };
        },

        onTreeNodeExpandClicked(e) {
            this.props.onTreeNodeExpandClicked.call(null, e, this.props.treeNode);
        },

        onTreeNodeOperationClicked(e) {
            this.props.onTreeNodeOperationClicked.call(null, e, this.props.treeNode);
        },

        onTreeNodeClicked(e) {
            this.props.onTreeNodeClicked.call(null, e, this.props.treeNode);
        },

        render() {
            let {
                treeNode,
                nameFilter,
                isExpanded,
                textLoading,
                className,
                ...other
            } = this.props;

            className = [
                'fcui2-tree-node',
                className
            ];

            if (treeNode.isChildrenLoaded && (treeNode.children == null || treeNode.children.length === 0)) {
                className.push('fcui2-tree-node-leaf');
            }

            if (nameFilter != null && treeNode.name.indexOf(nameFilter) === -1) {
                className.push('fcui2-tree-node-filtered');
            }

            return (

                    {treeNode.name}
                    {
                        treeNode.isChildrenLoading
                            ? {textLoading}
                            : ''
                    }

            );
        }
    });

    let Tree = React.createClass({
        propTypes: {
            /**
             * 树所展现的所有节点集合
             */
            treeNodes: React.PropTypes.arrayOf(treeNodeType),
            /**
             * 本层次树的上层节点
             */
            parentTreeNodes: React.PropTypes.arrayOf(treeNodeType),
            /**
             * 根据节点的层数，计算当前层的wrapper的style
             * @param {number} level 树的层数
             * @return {Object} 当前层的style object
             */
            getTreeLevelStyle: React.PropTypes.func,
            /**
             * 树节点展开按钮被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeExpandClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeExpandClicked.treeNode 被展开的树节点数据
             * @param {Array<treeNodeType>} onTreeNodeExpandClicked.parentTreeNodes 当前节点的父节点列表
             */
            onTreeNodeExpandClicked: React.PropTypes.func,
            /**
             * 树节点“操作”按钮被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeOperationClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeOperationClicked.treeNode 被操作的树节点数据
             * @param {Array<treeNodeType>} onTreeNodeOperationClicked.parentTreeNodes 当前节点的父节点列表
             */
            onTreeNodeOperationClicked: React.PropTypes.func,
            /**
             * 树节点其他位置被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeClicked.treeNode 被操作的树节点数据
             * @param {Array<treeNodeType>} onTreeNodeClicked.parentTreeNodes 当前节点的父节点列表
             */
            onTreeNodeClicked: React.PropTypes.func,
            /**
             * 节点加载中时的话术
             */
            textLoading: React.PropTypes.string,
            /**
             * 需要高亮显示的节点
             */
            focusedTreeNodeId: React.PropTypes.string,
            /**
             * filter string，不显示name中含有nameFilterString的node
             */
            nameFilter: React.PropTypes.string,
            /**
             * 被展开的节点集合
             */
            expandedTreeNodeId: React.PropTypes.objectOf(React.PropTypes.bool),
            /**
             * 被标记的节点集合
             */
            markedTreeNodeId: React.PropTypes.objectOf(React.PropTypes.bool)
        },

        statics: {
            treeNodeType
        },

        getDefaultProps() {
            return {
                treeLevel: 0,
                onTreeNodeExpandClicked: _.noop,
                onTreeNodeOperationClicked: _.noop,
                onTreeNodeClicked: _.noop,
                markedTreeNodeId: {},
                textLoading: '加载中...',
                nameFilter: null,
                parentTreeNodes: [],
                getTreeLevelStyle(level) {
                    return {
                        paddingLeft: (level * 0.5) + 'em'
                    };
                },
            };
        },

        getInitialState() {
            return {
                focusedTreeNodeId: this.props.focusedTreeNodeId || '',
                expandedTreeNodeId: this.props.expandedTreeNodeId || {},
                markedTreeNodeId: this.props.markedTreeNodeId || {}
            };
        },

        componentWillReceiveProps(nextProps) {
            this.setState(_.pick(nextProps, 'focusedTreeNodeId', 'expandedTreeNodeId', 'markedTreeNodeId'));
        },

        onTreeNodeExpandClicked(e, treeNode, parentTreeNodes) {
            if (this.props.parentTreeNodes.length) {
                this.props.onTreeNodeExpandClicked.apply(
                    null, e, treeNode, parentTreeNodes || this.props.parentTreeNodes
                );
                return;
            }

            this.props.onTreeNodeExpandClicked.apply(null, arguments);

            if (e.isDefaultPrevented()) {
                return;
            }

            let expandedTreeNodeId;

            if (this.state.expandedTreeNodeId[treeNode.id]) {
                expandedTreeNodeId = _.omit(this.state.expandedTreeNodeId, treeNode.id);
            }
            else {
                expandedTreeNodeId = _.extend({}, this.state.expandedTreeNodeId);
                expandedTreeNodeId[treeNode.id] = true;
            }
            this.setState({
                expandedTreeNodeId: expandedTreeNodeId
            });
        },

        onTreeNodeClicked(e, treeNode, parentTreeNodes) {
            if (this.props.parentTreeNodes.length) {
                this.props.onTreeNodeClicked.apply(
                    null, e, treeNode, parentTreeNodes || this.props.parentTreeNodes
                );
                return;
            }

            this.props.onTreeNodeClicked.apply(null, arguments);

            if (e.isDefaultPrevented()) {
                return;
            }

            this.setState({
                focusedTreeNodeId: treeNode.id
            });
        },

        onTreeNodeOperationClicked(e, treeNode, parentTreeNodes) {
            if (this.props.parentTreeNodes.length) {
                this.props.onTreeNodeOperationClicked.apply(
                    null, e, treeNode, parentTreeNodes || this.props.parentTreeNodes
                );
                return;
            }

            this.props.onTreeNodeOperationClicked.apply(null, arguments);
        },

        getHandlers() {
            return {
                onTreeNodeExpandClicked: this.onTreeNodeExpandClicked,
                onTreeNodeClicked: this.onTreeNodeClicked,
                onTreeNodeOperationClicked: this.onTreeNodeOperationClicked
            }
        },

        getTreeNodeProps() {
            return _.extend(
                _.pick(this.props, 'textLoading', 'treeLevel', 'nameFilter'),
                this.getHandlers()
            );
        },

        getInnerTreeProps() {
            return _.extend(
                _.omit(this.props, 'className', 'style'),
                _.pick(this.state, 'focusedTreeNodeId', 'expandedTreeNodeId'),
                this.getHandlers()
            );
        },

        getTreeNode(treeNode) {
            let isExpanded = !!this.state.expandedTreeNodeId[treeNode.id];
            let isMarked = !!this.state.markedTreeNodeId[treeNode.id];
            return (

                    <TreeNode
                        {...this.getTreeNodeProps()}
                        treeNode={treeNode}
                        isExpanded={isExpanded}
                        className={[
                            this.state.focusedTreeNodeId === treeNode.id ? 'fcui2-tree-node-focused' : '',
                            isMarked ? 'fcui2-tree-node-marked' : ''
                        ].join(' ')}
                    />
                    {
                        isExpanded && treeNode.children && treeNode.children.length
                            ? (
                                <Tree
                                    {...this.getInnerTreeProps()}
                                    parentTreeNodes={this.props.parentTreeNodes.concat(treeNode)}
                                    treeNodes={treeNode.children}
                                 />
                            )
                            : ''
                    }

            );
        },

        render() {
            let {
                getTreeLevelStyle,
                style,
                className = '',
                ...other
            } = this.props;

            let treeLevel = this.props.parentTreeNodes.length;

            return (

 0 ? 'fcui2-tree fcui2-tree-inner' : 'fcui2-tree'
                    ].join(' ')}
                >
                    {this.props.treeNodes.map(this.getTreeNode)}

            );
        }
    });

    return Tree;
});
<commit_msg>Tree.jsx.js fix fecs check<commit_after>/**
 * @file 一个树形选择控件。
 * @author Han Bing Feng (hanbingfeng@baidu.com)
 */

define(function (require) {
    let _ = require('underscore');
    let React = require('react');

    /**
     * 一个树节点的定义
     */
    let treeNodeType = React.PropTypes.shape({
        /**
         * 树节点id
         */
        id: React.PropTypes.string,
        /**
         * 树节点文本内容
         */
        name: React.PropTypes.string,
        /**
         * 树节点的 载入中 状态
         */
        isChildrenLoading: React.PropTypes.bool,
        /**
         * 树节点的 已载入 状态
         */
        isChildrenLoaded: React.PropTypes.bool,
        /**
         * 所有孩子
         */
        children: React.PropTypes.arrayOf(treeNodeType)
    });

    let TreeNode = React.createClass({
        propTypes: {
            /**
             * 树节点
             */
            treeNode: treeNodeType,
            /**
             * 树名字过滤器，不包含过滤器中字符串的节点将加上class`fcui2-tree-node-filtered`。
             */
            nameFilter: React.PropTypes.string,
            /**
             * 树节点是否被展开。
             */
            isExpanded: React.PropTypes.bool,
            /**
             * 树节点展开按钮被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeExpandClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeExpandClicked.treeNode 被展开的树节点数据
             */
            onTreeNodeExpandClicked: React.PropTypes.func,
            /**
             * 树节点“操作”按钮被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeOperationClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeOperationClicked.treeNode 被操作的树节点数据
             */
            onTreeNodeOperationClicked: React.PropTypes.func,
            /**
             * 树节点其他位置被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeClicked.treeNode 被操作的树节点数据
             */
            onTreeNodeClicked: React.PropTypes.func,
            /**
             * 树节点载入中时的话术提示。
             * @type {[type]}
             */
            textLoading: React.PropTypes.string,
            /**
             * 树节点根节点附加的class。
             */
            className: React.PropTypes.string
        },

        getDefaultProps() {
            return {
                onTreeNodeExpandClicked: _.noop,
                onTreeNodeOperationClicked: _.noop,
                onTreeNodeClicked: _.noop
            };
        },

        onTreeNodeExpandClicked(e) {
            this.props.onTreeNodeExpandClicked.call(null, e, this.props.treeNode);
        },

        onTreeNodeOperationClicked(e) {
            this.props.onTreeNodeOperationClicked.call(null, e, this.props.treeNode);
        },

        onTreeNodeClicked(e) {
            this.props.onTreeNodeClicked.call(null, e, this.props.treeNode);
        },

        render() {
            let {
                treeNode,
                nameFilter,
                isExpanded,
                textLoading,
                className,
                ...other
            } = this.props;

            className = [
                'fcui2-tree-node',
                className
            ];

            if (treeNode.isChildrenLoaded && (treeNode.children == null || treeNode.children.length === 0)) {
                className.push('fcui2-tree-node-leaf');
            }

            if (nameFilter != null && treeNode.name.indexOf(nameFilter) === -1) {
                className.push('fcui2-tree-node-filtered');
            }

            return (

                    {treeNode.name}
                    {
                        treeNode.isChildrenLoading
                            ? {textLoading}
                            : ''
                    }

            );
        }
    });

    let Tree = React.createClass({
        propTypes: {
            /**
             * 树所展现的所有节点集合
             */
            treeNodes: React.PropTypes.arrayOf(treeNodeType),
            /**
             * 本层次树的上层节点
             */
            parentTreeNodes: React.PropTypes.arrayOf(treeNodeType),
            /**
             * 根据节点的层数，计算当前层的wrapper的style
             * @param {number} level 树的层数
             * @return {Object} 当前层的style object
             */
            getTreeLevelStyle: React.PropTypes.func,
            /**
             * 树节点展开按钮被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeExpandClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeExpandClicked.treeNode 被展开的树节点数据
             * @param {Array<treeNodeType>} onTreeNodeExpandClicked.parentTreeNodes 当前节点的父节点列表
             */
            onTreeNodeExpandClicked: React.PropTypes.func,
            /**
             * 树节点“操作”按钮被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeOperationClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeOperationClicked.treeNode 被操作的树节点数据
             * @param {Array<treeNodeType>} onTreeNodeOperationClicked.parentTreeNodes 当前节点的父节点列表
             */
            onTreeNodeOperationClicked: React.PropTypes.func,
            /**
             * 树节点其他位置被点击时的回调。
             * @param {SyntheticEvent} onTreeNodeClicked.e 点击事件对象
             * @param {treeNodeType} onTreeNodeClicked.treeNode 被操作的树节点数据
             * @param {Array<treeNodeType>} onTreeNodeClicked.parentTreeNodes 当前节点的父节点列表
             */
            onTreeNodeClicked: React.PropTypes.func,
            /**
             * 节点加载中时的话术
             */
            textLoading: React.PropTypes.string,
            /**
             * 需要高亮显示的节点
             */
            focusedTreeNodeId: React.PropTypes.string,
            /**
             * filter string，不显示name中含有nameFilterString的node
             */
            nameFilter: React.PropTypes.string,
            /**
             * 被展开的节点集合
             */
            expandedTreeNodeId: React.PropTypes.objectOf(React.PropTypes.bool),
            /**
             * 被标记的节点集合
             */
            markedTreeNodeId: React.PropTypes.objectOf(React.PropTypes.bool)
        },

        statics: {
            treeNodeType
        },

        getDefaultProps() {
            return {
                treeLevel: 0,
                onTreeNodeExpandClicked: _.noop,
                onTreeNodeOperationClicked: _.noop,
                onTreeNodeClicked: _.noop,
                markedTreeNodeId: {},
                textLoading: '加载中...',
                nameFilter: null,
                parentTreeNodes: [],
                getTreeLevelStyle(level) {
                    return {
                        paddingLeft: (level * 0.5) + 'em'
                    };
                }
            };
        },

        getInitialState() {
            return {
                focusedTreeNodeId: this.props.focusedTreeNodeId || '',
                expandedTreeNodeId: this.props.expandedTreeNodeId || {},
                markedTreeNodeId: this.props.markedTreeNodeId || {}
            };
        },

        componentWillReceiveProps(nextProps) {
            this.setState(_.pick(nextProps, 'focusedTreeNodeId', 'expandedTreeNodeId', 'markedTreeNodeId'));
        },

        onTreeNodeExpandClicked(e, treeNode, parentTreeNodes) {
            if (this.props.parentTreeNodes.length) {
                this.props.onTreeNodeExpandClicked.apply(
                    null, e, treeNode, parentTreeNodes || this.props.parentTreeNodes
                );
                return;
            }

            this.props.onTreeNodeExpandClicked.apply(null, arguments);

            if (e.isDefaultPrevented()) {
                return;
            }

            let expandedTreeNodeId;

            if (this.state.expandedTreeNodeId[treeNode.id]) {
                expandedTreeNodeId = _.omit(this.state.expandedTreeNodeId, treeNode.id);
            }
            else {
                expandedTreeNodeId = _.extend({}, this.state.expandedTreeNodeId);
                expandedTreeNodeId[treeNode.id] = true;
            }
            this.setState({
                expandedTreeNodeId
            });
        },

        onTreeNodeClicked(e, treeNode, parentTreeNodes) {
            if (this.props.parentTreeNodes.length) {
                this.props.onTreeNodeClicked.apply(
                    null, e, treeNode, parentTreeNodes || this.props.parentTreeNodes
                );
                return;
            }

            this.props.onTreeNodeClicked.apply(null, arguments);

            if (e.isDefaultPrevented()) {
                return;
            }

            this.setState({
                focusedTreeNodeId: treeNode.id
            });
        },

        onTreeNodeOperationClicked(e, treeNode, parentTreeNodes) {
            if (this.props.parentTreeNodes.length) {
                this.props.onTreeNodeOperationClicked.apply(
                    null, e, treeNode, parentTreeNodes || this.props.parentTreeNodes
                );
                return;
            }

            this.props.onTreeNodeOperationClicked.apply(null, arguments);
        },

        getHandlers() {
            return {
                onTreeNodeExpandClicked: this.onTreeNodeExpandClicked,
                onTreeNodeClicked: this.onTreeNodeClicked,
                onTreeNodeOperationClicked: this.onTreeNodeOperationClicked
            };
        },

        getTreeNodeProps() {
            return _.extend(
                _.pick(this.props, 'textLoading', 'treeLevel', 'nameFilter'),
                this.getHandlers()
            );
        },

        getInnerTreeProps() {
            return _.extend(
                _.omit(this.props, 'className', 'style'),
                _.pick(this.state, 'focusedTreeNodeId', 'expandedTreeNodeId'),
                this.getHandlers()
            );
        },

        getTreeNode(treeNode) {
            let isExpanded = !!this.state.expandedTreeNodeId[treeNode.id];
            let isMarked = !!this.state.markedTreeNodeId[treeNode.id];
            return (

                    <TreeNode
                        {...this.getTreeNodeProps()}
                        treeNode={treeNode}
                        isExpanded={isExpanded}
                        className={[
                            this.state.focusedTreeNodeId === treeNode.id ? 'fcui2-tree-node-focused' : '',
                            isMarked ? 'fcui2-tree-node-marked' : ''
                        ].join(' ')}
                    />
                    {
                        isExpanded && treeNode.children && treeNode.children.length
                            ? (
                                <Tree
                                    {...this.getInnerTreeProps()}
                                    parentTreeNodes={this.props.parentTreeNodes.concat(treeNode)}
                                    treeNodes={treeNode.children}
                                 />
                            )
                            : ''
                    }

            );
        },

        render() {
            let {
                getTreeLevelStyle,
                style,
                className = '',
                ...other
            } = this.props;

            let treeLevel = this.props.parentTreeNodes.length;

            return (

 0 ? 'fcui2-tree fcui2-tree-inner' : 'fcui2-tree'
                    ].join(' ')}
                >
                    {this.props.treeNodes.map(this.getTreeNode)}

            );
        }
    });

    return Tree;
});
<|endoftext|>


<commit_before>import cloneDeep from 'lodash/cloneDeep';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';

import { AppIcon } from '@folio/stripes/core';
import {
  Paneset,
  Pane,
  PaneMenu,
  PaneHeaderIconButton,
  PaneFooter,
  Button,
  ExpandAllButton,
  expandAllFunction,
  Row,
  Col,
  Headline,
  AccordionSet
} from '@folio/stripes/components';
import stripesForm from '@folio/stripes/form';

import {
  EditUserInfo,
  EditExtendedInfo,
  EditContactInfo,
  EditProxy,
  EditUserPerms,
  EditServicePoints,
} from './components/EditSections';

import { HasCommand } from './components/Commander';

import { getFullName } from './util';

import css from './UserForm.css';

function validate(values, props) {
  const errors = {};
  errors.personal = {};

  if (!values.personal || !values.personal.lastName) {
    errors.personal.lastName = <FormattedMessage id="ui-users.errors.missingRequiredField" />;
  }

  if (!values.username && values.creds && values.creds.password) {
    errors.username = <FormattedMessage id="ui-users.errors.missingRequiredUsername" />;
  }

  if (!props.initialValues.id && (!values.creds || !values.creds.password) && values.username) {
    errors.creds = { password: <FormattedMessage id="ui-users.errors.missingRequiredPassword" /> };
  }

  if (!values.patronGroup) {
    errors.patronGroup = <FormattedMessage id="ui-users.errors.missingRequiredPatronGroup" />;
  }

  if (!values.personal || !values.personal.preferredContactTypeId) {
    if (errors.personal) errors.personal.preferredContactTypeId = <FormattedMessage id="ui-users.errors.missingRequiredContactType" />;
    else errors.personal = { preferredContactTypeId: <FormattedMessage id="ui-users.errors.missingRequiredContactType" /> };
  }

  if (values.personal && values.personal.addresses) {
    errors.personal.addresses = [];
    values.personal.addresses.forEach((addr) => {
      const err = (!addr.addressType) ? { addressType: <FormattedMessage id="ui-users.errors.missingRequiredAddressType" /> } : {};
      errors.personal.addresses.push(err);
    });
  }

  if (values.servicePoints && values.preferredServicePoint === undefined) {
    errors.preferredServicePoint = <FormattedMessage id="ui-users.errors.missingRequiredPreferredServicePoint" />;
  }

  return errors;
}

function asyncValidateField(field, value, validator) {
  return new Promise((resolve, reject) => {
    const query = `(${field}=="${value}")`;
    validator.reset();

    return validator.GET({ params: { query } }).then((users) => {
      if (users.length > 0) {
        const error = { [field]: <FormattedMessage id={`ui-users.errors.${field}Unavailable`} /> };
        return reject(error);
      } else {
        return resolve();
      }
    });
  });
}

function asyncValidate(values, dispatch, props, blurredField) {
  const { parentMutator: { uniquenessValidator }, initialValues } = props;
  const { username, barcode } = values;
  const curValue = values[blurredField];
  const prevValue = initialValues[blurredField];

  // validate on blur
  if (blurredField && curValue && curValue !== prevValue) {
    return asyncValidateField(blurredField, curValue, uniquenessValidator);
  }

  const promises = [];

  // validate on submit
  if (username !== initialValues.username) {
    promises.push(asyncValidateField('username', username, uniquenessValidator));
  }

  if (barcode && barcode !== initialValues.barcode) {
    promises.push(asyncValidateField('barcode', barcode, uniquenessValidator));
  }

  return Promise.all(promises);
}

class UserForm extends React.Component {
  static propTypes = {
    stripes: PropTypes.shape({
      connect: PropTypes.func,
    }).isRequired,
    handleSubmit: PropTypes.func.isRequired,
    parentMutator: PropTypes.shape({ // eslint-disable-line react/no-unused-prop-types
      uniquenessValidator: PropTypes.shape({
        reset: PropTypes.func.isRequired,
        GET: PropTypes.func.isRequired,
      }).isRequired,
    }).isRequired,
    parentResources: PropTypes.object.isRequired,
    pristine: PropTypes.bool,
    submitting: PropTypes.bool,
    onCancel: PropTypes.func.isRequired,
    onSubmit: PropTypes.func.isRequired,
    initialValues: PropTypes.object.isRequired,
  };

  static defaultProps = {
    pristine: false,
    submitting: false,
  };

  constructor(props) {
    super();

    this.state = {
      sections: {
        editUserInfo: true,
        extendedInfo: true,
        contactInfo: true,
        proxy: false,
        permissions: false,
        servicePoints: false,
      },
    };

    this.handleExpandAll = this.handleExpandAll.bind(this);
    this.handleSectionToggle = this.handleSectionToggle.bind(this);
    this.toggleAllSections = this.toggleAllSections.bind(this);
    this.collapseAllSections = this.collapseAllSections.bind(this);
    this.expandAllSections = this.expandAllSections.bind(this);

    this.ignoreEnterKey = this.ignoreEnterKey.bind(this);
    this.closeButton = React.createRef();

    this.keyboardCommands = [
      {
        name: 'save',
        handler: this.handleSaveKeyCommand
      },
      {
        name: 'ignoreEnter',
        handler: this.ignoreEnterKey,
        shortcut: 'enter'
      },
      {
        name: 'cancel',
        handler: props.onCancel,
        shortcut: 'esc'
      },
      {
        name: 'expandAllSections',
        handler: this.expandAllSections,
      },
      {
        name: 'collapseAllSections',
        handler: this.collapseAllSections,
      }
    ];

    if (props.initialValues.id) {
      this.connectedEditUserPerms = props.stripes.connect(EditUserPerms);
    }
  }

  componentDidMount() {
    // focus first interactive thing so that shortcuts will work immediately.
    this.closeButton.current.focus();
  }

  getAddFirstMenu() {
    return (
      <PaneMenu>
        <FormattedMessage id="ui-users.crud.closeNewUserDialog">
          {ariaLabel => (
            <PaneHeaderIconButton
              id="clickable-closenewuserdialog"
              onClick={this.props.onCancel}
              ref={this.closeButton}
              ariaLabel={ariaLabel}
              icon="times"
            />
          )}
        </FormattedMessage>
      </PaneMenu>
    );
  }

  handleExpandAll(sections) {
    this.setState({ sections });
  }

  // eslint-disable-next-line class-methods-use-this
  ignoreEnterKey = (e) => {
    e.preventDefault();
  };

  handleSectionToggle({ id }) {
    this.setState((curState) => {
      const newState = cloneDeep(curState);
      newState.sections[id] = !newState.sections[id];

      return newState;
    });
  }

  toggleAllSections(expand) {
    this.setState((curState) => {
      const newSections = expandAllFunction(curState.sections, expand);

      return {
        sections: newSections
      };
    });
  }

  expandAllSections(e) {
    e.preventDefault();
    this.toggleAllSections(true);
  }

  collapseAllSections(e) {
    e.preventDefault();
    this.toggleAllSections(false);
  }

  handleSaveKeyCommand = (e) => {
    e.preventDefault();
    this.executeSave();
  };

  executeSave() {
    const {
      handleSubmit,
      onSubmit,
    } = this.props;

    const submitter = handleSubmit(onSubmit);

    submitter();
  }

  getPaneFooter() {
    const {
      pristine,
      submitting,
      invalid,
      onCancel,
    } = this.props;

    const disabled = pristine || submitting || invalid;

    return (
      <PaneFooter>
        <Button
          data-test-user-form-cancel-button
          buttonStyle="default mega"
          onClick={onCancel}
        >
          <FormattedMessage id="ui-users.cancel" />
        </Button>
        <Button
          data-test-user-form-submit-button
          buttonStyle="primary mega"
          type="submit"
          disabled={disabled}
        >
          <FormattedMessage id="ui-users.saveAndClose" />
        </Button>
      </PaneFooter>
    );
  }

  render() {
    const {
      initialValues,
      handleSubmit,
      stripes: {
        connect,
      },
    } = this.props;

    const { sections } = this.state;
    const firstMenu = this.getAddFirstMenu();
    const footer = this.getPaneFooter();
    const paneTitle = initialValues.id
      ? getFullName(initialValues)
      : <FormattedMessage id="ui-users.crud.createUser" />;

    return (
      <HasCommand commands={this.keyboardCommands}>
        <form
          data-test-form-page
          className={css.UserFormRoot}
          id="form-user"
          onSubmit={handleSubmit}
        >
          <Paneset isRoot>
            <Pane
              defaultWidth="100%"
              firstMenu={firstMenu}
              footer={footer}
              appIcon={<AppIcon app="users" appIconKey="users" />}
              paneTitle={

                  {paneTitle}

              }
            >

                <Headline
                  size="xx-large"
                  tag="h2"
                  data-test-header-title
                >
                  {getFullName(initialValues)}
                </Headline>
                <Row end="xs">
                  <Col xs>
                    <ExpandAllButton
                      accordionStatus={sections}
                      onToggle={this.handleExpandAll}
                    />
                  </Col>
                </Row>
                <AccordionSet>
                  <EditUserInfo
                    accordionId="editUserInfo"
                    expanded={sections.editUserInfo}
                    onToggle={this.handleSectionToggle}
                    {...this.props}
                  />
                  <EditExtendedInfo
                    accordionId="extendedInfo"
                    expanded={sections.extendedInfo}
                    onToggle={this.handleSectionToggle}
                    userId={initialValues.id}
                    userFirstName={initialValues.personal.firstName}
                    userEmail={initialValues.personal.email}
                    stripesConnect={connect}
                  />
                  <EditContactInfo
                    accordionId="contactInfo"
                    expanded={sections.contactInfo}
                    onToggle={this.handleSectionToggle}
                    {...this.props}
                  />
                  {initialValues.id &&

                      <EditProxy
                        accordionId="proxy"
                        expanded={sections.proxy}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />
                      <this.connectedEditUserPerms
                        accordionId="permissions"
                        expanded={sections.permissions}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />
                      <EditServicePoints
                        accordionId="servicePoints"
                        expanded={sections.servicePoints}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />

                  }
                </AccordionSet>

            </Pane>
          </Paneset>
        </form>
      </HasCommand>
    );
  }
}

export default stripesForm({
  form: 'userForm',
  validate,
  asyncValidate,
  asyncBlurFields: ['username', 'barcode'],
  navigationCheck: true,
  enableReinitialize: true,
})(UserForm);
<commit_msg>STCOM-429: Prevent disabling user form submit button when it is `invalid` (#928)<commit_after>import cloneDeep from 'lodash/cloneDeep';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';

import { AppIcon } from '@folio/stripes/core';
import {
  Paneset,
  Pane,
  PaneMenu,
  PaneHeaderIconButton,
  PaneFooter,
  Button,
  ExpandAllButton,
  expandAllFunction,
  Row,
  Col,
  Headline,
  AccordionSet
} from '@folio/stripes/components';
import stripesForm from '@folio/stripes/form';

import {
  EditUserInfo,
  EditExtendedInfo,
  EditContactInfo,
  EditProxy,
  EditUserPerms,
  EditServicePoints,
} from './components/EditSections';

import { HasCommand } from './components/Commander';

import { getFullName } from './util';

import css from './UserForm.css';

function validate(values, props) {
  const errors = {};
  errors.personal = {};

  if (!values.personal || !values.personal.lastName) {
    errors.personal.lastName = <FormattedMessage id="ui-users.errors.missingRequiredField" />;
  }

  if (!values.username && values.creds && values.creds.password) {
    errors.username = <FormattedMessage id="ui-users.errors.missingRequiredUsername" />;
  }

  if (!props.initialValues.id && (!values.creds || !values.creds.password) && values.username) {
    errors.creds = { password: <FormattedMessage id="ui-users.errors.missingRequiredPassword" /> };
  }

  if (!values.patronGroup) {
    errors.patronGroup = <FormattedMessage id="ui-users.errors.missingRequiredPatronGroup" />;
  }

  if (!values.personal || !values.personal.preferredContactTypeId) {
    if (errors.personal) errors.personal.preferredContactTypeId = <FormattedMessage id="ui-users.errors.missingRequiredContactType" />;
    else errors.personal = { preferredContactTypeId: <FormattedMessage id="ui-users.errors.missingRequiredContactType" /> };
  }

  if (values.personal && values.personal.addresses) {
    errors.personal.addresses = [];
    values.personal.addresses.forEach((addr) => {
      const err = (!addr.addressType) ? { addressType: <FormattedMessage id="ui-users.errors.missingRequiredAddressType" /> } : {};
      errors.personal.addresses.push(err);
    });
  }

  if (values.servicePoints && values.preferredServicePoint === undefined) {
    errors.preferredServicePoint = <FormattedMessage id="ui-users.errors.missingRequiredPreferredServicePoint" />;
  }

  return errors;
}

function asyncValidateField(field, value, validator) {
  return new Promise((resolve, reject) => {
    const query = `(${field}=="${value}")`;
    validator.reset();

    return validator.GET({ params: { query } }).then((users) => {
      if (users.length > 0) {
        const error = { [field]: <FormattedMessage id={`ui-users.errors.${field}Unavailable`} /> };
        return reject(error);
      } else {
        return resolve();
      }
    });
  });
}

function asyncValidate(values, dispatch, props, blurredField) {
  const { parentMutator: { uniquenessValidator }, initialValues } = props;
  const { username, barcode } = values;
  const curValue = values[blurredField];
  const prevValue = initialValues[blurredField];

  // validate on blur
  if (blurredField && curValue && curValue !== prevValue) {
    return asyncValidateField(blurredField, curValue, uniquenessValidator);
  }

  const promises = [];

  // validate on submit
  if (username !== initialValues.username) {
    promises.push(asyncValidateField('username', username, uniquenessValidator));
  }

  if (barcode && barcode !== initialValues.barcode) {
    promises.push(asyncValidateField('barcode', barcode, uniquenessValidator));
  }

  return Promise.all(promises);
}

class UserForm extends React.Component {
  static propTypes = {
    stripes: PropTypes.shape({
      connect: PropTypes.func,
    }).isRequired,
    handleSubmit: PropTypes.func.isRequired,
    parentMutator: PropTypes.shape({ // eslint-disable-line react/no-unused-prop-types
      uniquenessValidator: PropTypes.shape({
        reset: PropTypes.func.isRequired,
        GET: PropTypes.func.isRequired,
      }).isRequired,
    }).isRequired,
    parentResources: PropTypes.object.isRequired,
    pristine: PropTypes.bool,
    submitting: PropTypes.bool,
    onCancel: PropTypes.func.isRequired,
    onSubmit: PropTypes.func.isRequired,
    initialValues: PropTypes.object.isRequired,
  };

  static defaultProps = {
    pristine: false,
    submitting: false,
  };

  constructor(props) {
    super();

    this.state = {
      sections: {
        editUserInfo: true,
        extendedInfo: true,
        contactInfo: true,
        proxy: false,
        permissions: false,
        servicePoints: false,
      },
    };

    this.handleExpandAll = this.handleExpandAll.bind(this);
    this.handleSectionToggle = this.handleSectionToggle.bind(this);
    this.toggleAllSections = this.toggleAllSections.bind(this);
    this.collapseAllSections = this.collapseAllSections.bind(this);
    this.expandAllSections = this.expandAllSections.bind(this);

    this.ignoreEnterKey = this.ignoreEnterKey.bind(this);
    this.closeButton = React.createRef();

    this.keyboardCommands = [
      {
        name: 'save',
        handler: this.handleSaveKeyCommand
      },
      {
        name: 'ignoreEnter',
        handler: this.ignoreEnterKey,
        shortcut: 'enter'
      },
      {
        name: 'cancel',
        handler: props.onCancel,
        shortcut: 'esc'
      },
      {
        name: 'expandAllSections',
        handler: this.expandAllSections,
      },
      {
        name: 'collapseAllSections',
        handler: this.collapseAllSections,
      }
    ];

    if (props.initialValues.id) {
      this.connectedEditUserPerms = props.stripes.connect(EditUserPerms);
    }
  }

  componentDidMount() {
    // focus first interactive thing so that shortcuts will work immediately.
    this.closeButton.current.focus();
  }

  getAddFirstMenu() {
    return (
      <PaneMenu>
        <FormattedMessage id="ui-users.crud.closeNewUserDialog">
          {ariaLabel => (
            <PaneHeaderIconButton
              id="clickable-closenewuserdialog"
              onClick={this.props.onCancel}
              ref={this.closeButton}
              ariaLabel={ariaLabel}
              icon="times"
            />
          )}
        </FormattedMessage>
      </PaneMenu>
    );
  }

  handleExpandAll(sections) {
    this.setState({ sections });
  }

  // eslint-disable-next-line class-methods-use-this
  ignoreEnterKey = (e) => {
    e.preventDefault();
  };

  handleSectionToggle({ id }) {
    this.setState((curState) => {
      const newState = cloneDeep(curState);
      newState.sections[id] = !newState.sections[id];

      return newState;
    });
  }

  toggleAllSections(expand) {
    this.setState((curState) => {
      const newSections = expandAllFunction(curState.sections, expand);

      return {
        sections: newSections
      };
    });
  }

  expandAllSections(e) {
    e.preventDefault();
    this.toggleAllSections(true);
  }

  collapseAllSections(e) {
    e.preventDefault();
    this.toggleAllSections(false);
  }

  handleSaveKeyCommand = (e) => {
    e.preventDefault();
    this.executeSave();
  };

  executeSave() {
    const {
      handleSubmit,
      onSubmit,
    } = this.props;

    const submitter = handleSubmit(onSubmit);

    submitter();
  }

  getPaneFooter() {
    const {
      pristine,
      submitting,
      onCancel,
    } = this.props;

    const disabled = pristine || submitting;

    return (
      <PaneFooter>
        <Button
          data-test-user-form-cancel-button
          buttonStyle="default mega"
          onClick={onCancel}
        >
          <FormattedMessage id="ui-users.cancel" />
        </Button>
        <Button
          data-test-user-form-submit-button
          buttonStyle="primary mega"
          type="submit"
          disabled={disabled}
        >
          <FormattedMessage id="ui-users.saveAndClose" />
        </Button>
      </PaneFooter>
    );
  }

  render() {
    const {
      initialValues,
      handleSubmit,
      stripes: {
        connect,
      },
    } = this.props;

    const { sections } = this.state;
    const firstMenu = this.getAddFirstMenu();
    const footer = this.getPaneFooter();
    const paneTitle = initialValues.id
      ? getFullName(initialValues)
      : <FormattedMessage id="ui-users.crud.createUser" />;

    return (
      <HasCommand commands={this.keyboardCommands}>
        <form
          data-test-form-page
          className={css.UserFormRoot}
          id="form-user"
          onSubmit={handleSubmit}
        >
          <Paneset isRoot>
            <Pane
              defaultWidth="100%"
              firstMenu={firstMenu}
              footer={footer}
              appIcon={<AppIcon app="users" appIconKey="users" />}
              paneTitle={

                  {paneTitle}

              }
            >

                <Headline
                  size="xx-large"
                  tag="h2"
                  data-test-header-title
                >
                  {getFullName(initialValues)}
                </Headline>
                <Row end="xs">
                  <Col xs>
                    <ExpandAllButton
                      accordionStatus={sections}
                      onToggle={this.handleExpandAll}
                    />
                  </Col>
                </Row>
                <AccordionSet>
                  <EditUserInfo
                    accordionId="editUserInfo"
                    expanded={sections.editUserInfo}
                    onToggle={this.handleSectionToggle}
                    {...this.props}
                  />
                  <EditExtendedInfo
                    accordionId="extendedInfo"
                    expanded={sections.extendedInfo}
                    onToggle={this.handleSectionToggle}
                    userId={initialValues.id}
                    userFirstName={initialValues.personal.firstName}
                    userEmail={initialValues.personal.email}
                    stripesConnect={connect}
                  />
                  <EditContactInfo
                    accordionId="contactInfo"
                    expanded={sections.contactInfo}
                    onToggle={this.handleSectionToggle}
                    {...this.props}
                  />
                  {initialValues.id &&

                      <EditProxy
                        accordionId="proxy"
                        expanded={sections.proxy}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />
                      <this.connectedEditUserPerms
                        accordionId="permissions"
                        expanded={sections.permissions}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />
                      <EditServicePoints
                        accordionId="servicePoints"
                        expanded={sections.servicePoints}
                        onToggle={this.handleSectionToggle}
                        {...this.props}
                      />

                  }
                </AccordionSet>

            </Pane>
          </Paneset>
        </form>
      </HasCommand>
    );
  }
}

export default stripesForm({
  form: 'userForm',
  validate,
  asyncValidate,
  asyncBlurFields: ['username', 'barcode'],
  navigationCheck: true,
  enableReinitialize: true,
})(UserForm);
<|endoftext|>


<commit_before>/**
 *
 */

VK.init({
    apiId: 1755175
});

var WRONG_TEXT = 'Something goes wrong. Enter valid post address.';

var grp = '';
var us = '';
var grpAvatar = '';

var obj = [];
var parsed = [0, 0];

var grCount = 0;
var grOffset = 0;

var sexArray = [];

function getGroupInfo(groupId) {

    VK.api("groups.getById", { 'group_id': Math.abs(groupId), 'fields': 'members_count,photo_100' }, function (data) {
        if (data.error) {
            errorMSG('Error in data. Wrong group data.')
        }else{
            for (var i = 0; i < data.response.length; i++) {
                grp = data.response[i].name;
                us = data.response[i].members_count;
                grpAvatar = data.response[i].photo_100;

                obj[0] = grp;
                obj[1] = us;
                obj[2] = grpAvatar;

            }
            groupViewChanges(getGroupData());
        }
	});

    waiting();//wait
    getGroupMembers(parsed);
}

function getGroupMembers(objTargets){ //,memCount,offset) {
    var aboutPost = objTargets; // 0-group, 1-item_post
    var code = '';
    console.log(aboutPost[0],aboutPost[1]);
    /*code = 'var c=0;var co=1000;var p=[];var i=0;var o=0;var u=[];'+
        'while(i!=10) {var li=API.likes.getList({"type":"post","owner_id":'+aboutPost[0]+',"item_id":'+aboutPost[1]+',"filter":"likes","friends_only":0,"offset":o,"count":co});'+
        'c=li.count;u=u+API.users.get({"user_ids":li.items,"fields":"sex"})@.sex;i=i+1;o=o+co;}'+
        'return {"count":c,"user":u,"l":u.length};';*/
    code = 'var c=0;var u=[];' +
        +'var li=API.likes.getList({"type":"post","owner_id":' +
        + aboutPost[0] + ',"item_id":' + aboutPost[1] + ',"filter":"likes","friends_only":0,"offset":0,"count":1000});' +
        +'c=li.count;var s=API.users.get({"user_ids":li.items,"fields":"sex"}); u=u+s@.sex;' +
        +'return {"count":c,"user":u,"l":u.length};';

    VK.api('execute', { 'code': code, }, function (data) {
        console.log(data);
        if (data.response.error) {
            errorMSG('Wrong: Group Member');
            console.log("error");
        } else {

        }
    });
}

function getGroupData() {
    return obj;
}

function getParsedInfo() {
    return parsed;
}

function waiting() {
    var se = 0;
    setTimeout(function () {
        if (se++ > 1) {
            waiting();
            console.log('wait');
        }
    }, 400);
}

    function groupViewChanges(obj) {
        var a = obj;
        document.getElementById('groupName').innerHTML = 'Name: '+a[0];
        document.getElementById('members_count').innerHTML = 'Count: '+a[1];
        document.getElementById('av').src = a[2];
    }

    function parseLink() {
        var link = String(document.getElementById('post').value);

        if (link != '' && (link.match('vk.com') == 'vk.com') && (link.match('wall-') == 'wall-')) {

            if (link.indexOf('=wall') != -1) {
                var adr = link.substring(link.indexOf('=wall') + 5, link.length);
                var p = adr.split('_');
                if ((p[0] === undefined) && (p[1] === undefined)) {
                    errorMSG('Wrong: group or post or both');
                } else {
                    if ((/\d+/.test(p[0])) && (/\d+/.test(p[1]))) {
                        parsed[0] = p[0]; parsed[1] = p[1];
                        getGroupInfo(parsed[0]);
                    }

                }
            } else {
                errorMSG('Wrong: not wall post');
            }
        }else{
            errorMSG('Wrong: not vk.com');
        }
    }

    function clearadress() {
        document.getElementById('post').value = '';
    }

    function errorMSG(msg) {
        document.getElementById('post').value = msg;
        setTimeout(clearadress, 1000);
    }<commit_msg>43gfvv<commit_after>/**
 *
 */

VK.init({
    apiId: 1755175
});

var WRONG_TEXT = 'Something goes wrong. Enter valid post address.';

var grp = '';
var us = '';
var grpAvatar = '';

var obj = [];
var parsed = [0, 0];

var grCount = 0;
var grOffset = 0;

var sexArray = [];

function getGroupInfo(groupId) {

    VK.api("groups.getById", { 'group_id': Math.abs(groupId), 'fields': 'members_count,photo_100' }, function (data) {
        if (data.error) {
            errorMSG('Error in data. Wrong group data.')
        }else{
            for (var i = 0; i < data.response.length; i++) {
                grp = data.response[i].name;
                us = data.response[i].members_count;
                grpAvatar = data.response[i].photo_100;

                obj[0] = grp;
                obj[1] = us;
                obj[2] = grpAvatar;

            }
            groupViewChanges(getGroupData());
        }
	});

    waiting();//wait
    getGroupMembers(parsed);
}

function getGroupMembers(objTargets){ //,memCount,offset) {
    var aboutPost = objTargets; // 0-group, 1-item_post
    var code = '';
    console.log(aboutPost[0],aboutPost[1]);
    /*code = 'var c=0;var co=1000;var p=[];var i=0;var o=0;var u=[];'+
        'while(i!=10) {var li=API.likes.getList({"type":"post","owner_id":'+aboutPost[0]+',"item_id":'+aboutPost[1]+',"filter":"likes","friends_only":0,"offset":o,"count":co});'+
        'c=li.count;u=u+API.users.get({"user_ids":li.items,"fields":"sex"})@.sex;i=i+1;o=o+co;}'+
        'return {"count":c,"user":u,"l":u.length};';*/
    code = 'var c=0;var u=[];' +
        +'var li=API.likes.getList({"type":"post","owner_id":' +
        + '-10639516' + ',"item_id":' + '58468105' + ',"filter":"likes","friends_only":0,"offset":0,"count":1000});' +
        +'c=li.count;var s=API.users.get({"user_ids":li.items,"fields":"sex"}); u=u+s@.sex;' +
        +'return {"count":c,"user":u,"l":u.length};';
    //http://vk.com/mdk?w=wall-10639516_58468105
    VK.api('execute', { 'code': code, }, function (data) {
        console.log(data);
        if (data.response.error) {
            errorMSG('Wrong: Group Member');
            console.log("error");
        } else {

        }
    });
}

function getGroupData() {
    return obj;
}

function getParsedInfo() {
    return parsed;
}

function waiting() {
    var se = 0;
    setTimeout(function () {
        if (se++ > 1) {
            waiting();
            console.log('wait');
        }
    }, 400);
}

    function groupViewChanges(obj) {
        var a = obj;
        document.getElementById('groupName').innerHTML = 'Name: '+a[0];
        document.getElementById('members_count').innerHTML = 'Count: '+a[1];
        document.getElementById('av').src = a[2];
    }

    function parseLink() {
        var link = String(document.getElementById('post').value);

        if (link != '' && (link.match('vk.com') == 'vk.com') && (link.match('wall-') == 'wall-')) {

            if (link.indexOf('=wall') != -1) {
                var adr = link.substring(link.indexOf('=wall') + 5, link.length);
                var p = adr.split('_');
                if ((p[0] === undefined) && (p[1] === undefined)) {
                    errorMSG('Wrong: group or post or both');
                } else {
                    if ((/\d+/.test(p[0])) && (/\d+/.test(p[1]))) {
                        parsed[0] = p[0]; parsed[1] = p[1];
                        getGroupInfo(parsed[0]);
                    }

                }
            } else {
                errorMSG('Wrong: not wall post');
            }
        }else{
            errorMSG('Wrong: not vk.com');
        }
    }

    function clearadress() {
        document.getElementById('post').value = '';
    }

    function errorMSG(msg) {
        document.getElementById('post').value = msg;
        setTimeout(clearadress, 1000);
    }<|endoftext|>


<commit_before>(function($, undefined) {
  $(function() {
    var mapElements = $('[data-map]');
    for (var mi = 0, len = mapElements.length; mi < len; mi++) {
      var mapElement = $(mapElements[mi]);
      eval('var mapData = ' + mapElement.data('map'));
      mapData.map.div = '#' + mapElement.attr('id');
      var map = new GMaps(mapData.map);
      for (var di = 0, dlen = mapData.directives.length; di < dlen; di++) {
        var d = mapData.directives[di];
        map[d.name].apply(map, d.args);
      }
    }
  });
})( jQuery );
<commit_msg>Make gmaps-ujs turbolinks-friendly<commit_after>(function($, undefined) {
  var gmapsUjs = function() {
    var mapElements = $('[data-map]');
    for (var mi = 0, len = mapElements.length; mi < len; mi++) {
      var mapElement = $(mapElements[mi]);
      eval('var mapData = ' + mapElement.data('map'));
      mapData.map.div = '#' + mapElement.attr('id');
      var map = new GMaps(mapData.map);
      for (var di = 0, dlen = mapData.directives.length; di < dlen; di++) {
        var d = mapData.directives[di];
        map[d.name].apply(map, d.args);
      }
    }
  };

  if ((typeof Turbolinks === 'undefined') || $.turbo) {
    $(gmapsUjs);
  } else {
    $(document).on("page:change", gmapsUjs);
  }
})( jQuery );
<|endoftext|>


<commit_before>'use strict'

var createShader = require('gl-shader')
var createBuffer = require('gl-buffer')

var pool = require('typedarray-pool')

var SHADERS = require('./lib/shader')

module.exports = createScatter2D

function Scatter2D(plot, offsetBuffer, pickBuffer, shader, pickShader) {
  this.plot           = plot
  this.offsetBuffer   = offsetBuffer
  this.pickBuffer     = pickBuffer
  this.shader         = shader
  this.pickShader     = pickShader
  this.size           = 12.0
  this.borderSize     = 1.0
  this.pointCount     = 0
  this.color          = [1, 0, 0, 1]
  this.borderColor    = [0, 0, 0, 1]
  this.bounds         = [Infinity, Infinity, -Infinity, -Infinity]
  this.pickOffset     = 0
  this.points         = null
}

var proto = Scatter2D.prototype

proto.dispose = function() {
  this.shader.dispose()
  this.pickShader.dispose()
  this.offsetBuffer.dispose()
  this.pickBuffer.dispose()
  this.plot.removeObject(this)
}

proto.update = function(options) {

  var i

  options = options || {}

  function dflt(opt, value) {
    if(opt in options) {
      return options[opt]
    }
    return value
  }

  this.size         = dflt('size', 12.0)
  this.color        = dflt('color', [1, 0, 0, 1]).slice()
  this.borderSize   = dflt('borderSize', 1)
  this.borderColor  = dflt('borderColor', [0, 0, 0, 1]).slice()

  //Update point data
  var data          = options.positions
  var packed        = pool.mallocFloat32(data.length)
  var packedId      = pool.mallocInt32(data.length >>> 1)
  packed.set(data)
  this.points       = data

  var min = 0
  var max = 10
  this.bounds = [min, min, max, max]
  for(i = 0; i < data.length >>> 1; i++) {
    packedId[i] = i
  }
  for(i = 0; i < data.length; i++) {
    packed[i] = (packed[i] - min) / (max - min)
  }

  this.offsetBuffer.update(packed)
  this.pickBuffer.update(packedId)
  pool.free(packedId)
  pool.free(packed)

  this.pointCount = data.length >>> 1
  this.pickOffset = 0
}

function count(points, dataBox) {
  var visiblePointCountEstimate = 0
  var length = points.length >>> 1
  var i
  for(i = 0; i < length; i++) {
    var x = points[i * 2]
    var y = points[i * 2 + 1]
    if(x >= dataBox[0] && x <= dataBox[2] && y >= dataBox[1] && y <= dataBox[3])
      visiblePointCountEstimate++
  }
  return visiblePointCountEstimate
}

proto.unifiedDraw = (function() {
  var MATRIX = [1, 0, 0,
                0, 1, 0,
                0, 0, 1]
  var PICK_VEC4 = [0, 0, 0, 0]
return function(pickOffset) {

  var pick = pickOffset !== void(0)

  var shader        = pick ? this.pickShader : this.shader
  var gl            = this.plot.gl
  var dataBox       = this.plot.dataBox

  if(this.pointCount === 0) {
    return pickOffset
  }

  var boundX  = this.bounds[2] - this.bounds[0]
  var boundY  = this.bounds[3] - this.bounds[1]
  var dataX   = dataBox[2] - dataBox[0]
  var dataY   = dataBox[3] - dataBox[1]

  var visiblePointCountEstimate = count(this.points, dataBox)
  var basicPointSize =  this.plot.pickPixelRatio * Math.max(0.1, Math.min(30, 30 / Math.pow(visiblePointCountEstimate, 0.33333)))

  MATRIX[0] = 2.0 * boundX / dataX
  MATRIX[4] = 2.0 * boundY / dataY
  MATRIX[6] = 2.0 * (this.bounds[0] - dataBox[0]) / dataX - 1.0
  MATRIX[7] = 2.0 * (this.bounds[1] - dataBox[1]) / dataY - 1.0

  this.offsetBuffer.bind()

  shader.bind()
  shader.attributes.position.pointer()
  shader.uniforms.matrix      = MATRIX
  shader.uniforms.color       = this.color
  shader.uniforms.borderColor = this.borderColor
  shader.uniforms.pointCloud = shader.uniforms.pointSize < 5
  shader.uniforms.pointSize = basicPointSize * (shader.uniforms.pointCloud ? 1 : (this.size + this.borderSize) / this.size)
  shader.uniforms.centerFraction = this.borderSize === 0 ? 2.0 : this.size / (this.size + this.borderSize + 1.25)

  if(pick) {

    PICK_VEC4[0] = ( pickOffset        & 0xff)
    PICK_VEC4[1] = ((pickOffset >> 8)  & 0xff)
    PICK_VEC4[2] = ((pickOffset >> 16) & 0xff)
    PICK_VEC4[3] = ((pickOffset >> 24) & 0xff)

    this.pickBuffer.bind()
    shader.attributes.pickId.pointer(gl.UNSIGNED_BYTE)
    shader.uniforms.pickOffset = PICK_VEC4
    this.pickOffset = pickOffset
  }

  gl.drawArrays(gl.POINTS, 0, this.pointCount)

  return pickOffset + this.pointCount
}
})()

proto.draw = proto.unifiedDraw
proto.drawPick = proto.unifiedDraw

proto.pick = function(x, y, value) {
  var pickOffset = this.pickOffset
  var pointCount = this.pointCount
  if(value < pickOffset || value >= pickOffset + pointCount) {
    return null
  }
  var pointId = value - pickOffset
  var points = this.points
  return {
    object: this,
    pointId: pointId,
    dataCoord: [points[2 * pointId], points[2 * pointId + 1] ]
  }
}

function createScatter2D(plot, options) {
  var gl = plot.gl
  var buffer = createBuffer(gl)
  var pickBuffer = createBuffer(gl)
  var shader = createShader(gl, SHADERS.pointVertex, SHADERS.pointFragment)
  var pickShader = createShader(gl, SHADERS.pickVertex, SHADERS.pickFragment)

  var result = new Scatter2D(plot, buffer, pickBuffer, shader, pickShader)
  result.update(options)

  //Register with plot
  plot.addObject(result)

  return result
}
<commit_msg>renamings<commit_after>'use strict'

var createShader = require('gl-shader')
var createBuffer = require('gl-buffer')

var pool = require('typedarray-pool')

var SHADERS = require('./lib/shader')

module.exports = createPointcloud2D

function Pointcloud2D(plot, offsetBuffer, pickBuffer, shader, pickShader) {
  this.plot           = plot
  this.offsetBuffer   = offsetBuffer
  this.pickBuffer     = pickBuffer
  this.shader         = shader
  this.pickShader     = pickShader
  this.size           = 12.0
  this.borderSize     = 1.0
  this.pointCount     = 0
  this.color          = [1, 0, 0, 1]
  this.borderColor    = [0, 0, 0, 1]
  this.bounds         = [Infinity, Infinity, -Infinity, -Infinity]
  this.pickOffset     = 0
  this.points         = null
}

var proto = Pointcloud2D.prototype

proto.dispose = function() {
  this.shader.dispose()
  this.pickShader.dispose()
  this.offsetBuffer.dispose()
  this.pickBuffer.dispose()
  this.plot.removeObject(this)
}

proto.update = function(options) {

  var i

  options = options || {}

  function dflt(opt, value) {
    if(opt in options) {
      return options[opt]
    }
    return value
  }

  this.size         = dflt('size', 12.0)
  this.color        = dflt('color', [1, 0, 0, 1]).slice()
  this.borderSize   = dflt('borderSize', 1)
  this.borderColor  = dflt('borderColor', [0, 0, 0, 1]).slice()

  //Update point data
  var data          = options.positions
  var packed        = pool.mallocFloat32(data.length)
  var packedId      = pool.mallocInt32(data.length >>> 1)
  packed.set(data)
  this.points       = data

  var min = 0
  var max = 10
  this.bounds = [min, min, max, max]
  for(i = 0; i < data.length >>> 1; i++) {
    packedId[i] = i
  }
  for(i = 0; i < data.length; i++) {
    packed[i] = (packed[i] - min) / (max - min)
  }

  this.offsetBuffer.update(packed)
  this.pickBuffer.update(packedId)
  pool.free(packedId)
  pool.free(packed)

  this.pointCount = data.length >>> 1
  this.pickOffset = 0
}

function count(points, dataBox) {
  var visiblePointCountEstimate = 0
  var length = points.length >>> 1
  var i
  for(i = 0; i < length; i++) {
    var x = points[i * 2]
    var y = points[i * 2 + 1]
    if(x >= dataBox[0] && x <= dataBox[2] && y >= dataBox[1] && y <= dataBox[3])
      visiblePointCountEstimate++
  }
  return visiblePointCountEstimate
}

proto.unifiedDraw = (function() {
  var MATRIX = [1, 0, 0,
                0, 1, 0,
                0, 0, 1]
  var PICK_VEC4 = [0, 0, 0, 0]
return function(pickOffset) {

  var pick = pickOffset !== void(0)

  var shader        = pick ? this.pickShader : this.shader
  var gl            = this.plot.gl
  var dataBox       = this.plot.dataBox

  if(this.pointCount === 0) {
    return pickOffset
  }

  var boundX  = this.bounds[2] - this.bounds[0]
  var boundY  = this.bounds[3] - this.bounds[1]
  var dataX   = dataBox[2] - dataBox[0]
  var dataY   = dataBox[3] - dataBox[1]

  var visiblePointCountEstimate = count(this.points, dataBox)
  var basicPointSize =  this.plot.pickPixelRatio * Math.max(0.1, Math.min(30, 30 / Math.pow(visiblePointCountEstimate, 0.33333)))

  MATRIX[0] = 2.0 * boundX / dataX
  MATRIX[4] = 2.0 * boundY / dataY
  MATRIX[6] = 2.0 * (this.bounds[0] - dataBox[0]) / dataX - 1.0
  MATRIX[7] = 2.0 * (this.bounds[1] - dataBox[1]) / dataY - 1.0

  this.offsetBuffer.bind()

  shader.bind()
  shader.attributes.position.pointer()
  shader.uniforms.matrix      = MATRIX
  shader.uniforms.color       = this.color
  shader.uniforms.borderColor = this.borderColor
  shader.uniforms.pointCloud = shader.uniforms.pointSize < 5
  shader.uniforms.pointSize = basicPointSize * (shader.uniforms.pointCloud ? 1 : (this.size + this.borderSize) / this.size)
  shader.uniforms.centerFraction = this.borderSize === 0 ? 2.0 : this.size / (this.size + this.borderSize + 1.25)

  if(pick) {

    PICK_VEC4[0] = ( pickOffset        & 0xff)
    PICK_VEC4[1] = ((pickOffset >> 8)  & 0xff)
    PICK_VEC4[2] = ((pickOffset >> 16) & 0xff)
    PICK_VEC4[3] = ((pickOffset >> 24) & 0xff)

    this.pickBuffer.bind()
    shader.attributes.pickId.pointer(gl.UNSIGNED_BYTE)
    shader.uniforms.pickOffset = PICK_VEC4
    this.pickOffset = pickOffset
  }

  gl.drawArrays(gl.POINTS, 0, this.pointCount)

  return pickOffset + this.pointCount
}
})()

proto.draw = proto.unifiedDraw
proto.drawPick = proto.unifiedDraw

proto.pick = function(x, y, value) {
  var pickOffset = this.pickOffset
  var pointCount = this.pointCount
  if(value < pickOffset || value >= pickOffset + pointCount) {
    return null
  }
  var pointId = value - pickOffset
  var points = this.points
  return {
    object: this,
    pointId: pointId,
    dataCoord: [points[2 * pointId], points[2 * pointId + 1] ]
  }
}

function createPointcloud2D(plot, options) {
  var gl = plot.gl
  var buffer = createBuffer(gl)
  var pickBuffer = createBuffer(gl)
  var shader = createShader(gl, SHADERS.pointVertex, SHADERS.pointFragment)
  var pickShader = createShader(gl, SHADERS.pickVertex, SHADERS.pickFragment)

  var result = new Pointcloud2D(plot, buffer, pickBuffer, shader, pickShader)
  result.update(options)

  //Register with plot
  plot.addObject(result)

  return result
}
<|endoftext|>


<commit_before>'use strict';

let archiver = require('archiver');
let fs = require('fs');
let Heroku = require('heroku-client');
let ignore = require('ignore');
let uuid = require('node-uuid');
let os = require('os');
let path = require('path');
let request = require('request');

function uploadCwdToSource(app, cwd, fn) {
  let tempFilePath = path.join(os.tmpdir(), uuid.v4() + '.tar.gz');

  app.sources().create({}).then(function(source){
    let archive = archiver('tar', { gzip: true });

    archive.on('finish', function (err) {
      if (err) { throw err; }

      let filesize = fs.statSync(tempFilePath).size;
      let request_options = {
        url: source.source_blob.put_url,
        headers: {
         'Content-Type': '',
         'Content-Length': filesize
        }
      };

      var stream = fs.createReadStream(tempFilePath);
      stream.on('close', function() {
        fs.unlink(tempFilePath);
      });

      stream.pipe(request.put(request_options, function() {
        fn(source.source_blob.get_url);
      }));
    });

    let output = fs.createWriteStream(tempFilePath);
    archive.pipe(output);
    // TODO: Don't add things that we don't want
    // eg. `.git` and things in `.gitignore`
    var options = false;
    if (os.platform() == 'win32') {
      options = { mode: 0o0755 };
    }
    archive.directory(cwd, false, options).finalize();
  });
}

function create(context) {
  let heroku = new Heroku({ token: context.auth.password });
  let app = heroku.apps(context.app);

  var sourceUrl = context.args['source-url'];

  var sourceUrlPromise = sourceUrl ?
      new Promise(function(resolve) { resolve(sourceUrl);}) :
      new Promise(function(resolve) { uploadCwdToSource(app, context.cwd, resolve); });

  sourceUrlPromise.then(function(sourceGetUrl) {
    // TODO we have to bail out to `request` to get edge version
    heroku.request({
      path: `/apps/${context.app}/builds`,
      method: 'POST',
      headers: {
        'Accept': 'application/vnd.heroku+json; version=3.streaming-build-output'
      },
      parseJSON: true,
      body: {
        source_blob: {
          url: sourceGetUrl,
          // TODO provide better default, eg. archive md5
          version: context.args.version || ''
        }
      }
    }).then(function(build) {
      request.get(build.output_stream_url).pipe(process.stderr);
    }).done();
  });
}

module.exports = {
  topic: 'builds',
  command: 'create',
  needsAuth: true,
  needsApp: true,
  help: 'Create build from contents of current dir',
  description: 'create build',
  flags: [
    { name: 'source-url', description: 'Source URL that points to the tarball of your application\'s source code', hasValue: true},
    { name: 'version', description: 'Description of your new build', hasValue: true }
  ],
  run: create
};
<commit_msg>First stab at ignoring .git and .gitignore files<commit_after>'use strict';

let archiver = require('archiver');
let fs = require('fs');
let Heroku = require('heroku-client');
let ignore = require('ignore');
let uuid = require('node-uuid');
let os = require('os');
let path = require('path');
let request = require('request');

function uploadCwdToSource(app, cwd, fn) {
  let tempFilePath = path.join(os.tmpdir(), uuid.v4() + '.tar.gz');
  let ig = ignore().addIgnoreFile('.gitignore');
  let filter = ig.createFilter();

  app.sources().create({}).then(function(source){
    let archive = archiver('tar', { gzip: true });

    archive.on('finish', function (err) {
      if (err) { throw err; }

      let filesize = fs.statSync(tempFilePath).size;
      let request_options = {
        url: source.source_blob.put_url,
        headers: {
         'Content-Type': '',
         'Content-Length': filesize
        }
      };

      var stream = fs.createReadStream(tempFilePath);
      stream.on('close', function() {
        fs.unlink(tempFilePath);
      });

      stream.pipe(request.put(request_options, function() {
        fn(source.source_blob.get_url);
      }));
    });

    let output = fs.createWriteStream(tempFilePath);
    archive.pipe(output);
    var data = {};
    if (os.platform() == 'win32') {
      data.mode = 0o0755;
    }
    archive.bulk([
      { expand: true,
        cwd: cwd,
        src: ['*'],
        dest: false,
        filter: filter,
        data: data
      }
    ]).finalize();
  });
}

function create(context) {
  let heroku = new Heroku({ token: context.auth.password });
  let app = heroku.apps(context.app);

  var sourceUrl = context.args['source-url'];

  var sourceUrlPromise = sourceUrl ?
      new Promise(function(resolve) { resolve(sourceUrl);}) :
      new Promise(function(resolve) { uploadCwdToSource(app, context.cwd, resolve); });

  sourceUrlPromise.then(function(sourceGetUrl) {
    // TODO we have to bail out to `request` to get edge version
    heroku.request({
      path: `/apps/${context.app}/builds`,
      method: 'POST',
      headers: {
        'Accept': 'application/vnd.heroku+json; version=3.streaming-build-output'
      },
      parseJSON: true,
      body: {
        source_blob: {
          url: sourceGetUrl,
          // TODO provide better default, eg. archive md5
          version: context.args.version || ''
        }
      }
    }).then(function(build) {
      request.get(build.output_stream_url).pipe(process.stderr);
    }).done();
  });
}

module.exports = {
  topic: 'builds',
  command: 'create',
  needsAuth: true,
  needsApp: true,
  help: 'Create build from contents of current dir',
  description: 'create build',
  flags: [
    { name: 'source-url', description: 'Source URL that points to the tarball of your application\'s source code', hasValue: true},
    { name: 'version', description: 'Description of your new build', hasValue: true }
  ],
  run: create
};
<|endoftext|>


<commit_before>const Command = require('../command');

class ExportCommand extends Command {
    async run(argv) {
        const {exportTask} = require('../tasks/import');
        const {SystemError} = require('../errors');

        const instance = this.system.getInstance();
        const isRunning = await instance.isRunning();

        if (!isRunning) {
            const shouldStart = await this.ui.confirm('Ghost instance is not currently running. Would you like to start it?', true);

            if (!shouldStart) {
                throw new SystemError('Ghost instance is not currently running');
            }

            instance.checkEnvironment();
            await this.ui.run(() => instance.start(), 'Starting Ghost');
        }

        await this.ui.run(() => exportTask(this.ui, instance, argv.file), 'Exporting content');
        this.ui.log(`Content exported to ${argv.file}`, 'green');
    }
}

ExportCommand.description = 'Export content from a blog';
ExportCommand.params = '[file]';

module.exports = ExportCommand;
<commit_msg>fix(export): file is not optional<commit_after>const Command = require('../command');

class ExportCommand extends Command {
    async run(argv) {
        const {exportTask} = require('../tasks/import');
        const {SystemError} = require('../errors');

        const instance = this.system.getInstance();
        const isRunning = await instance.isRunning();

        if (!isRunning) {
            const shouldStart = await this.ui.confirm('Ghost instance is not currently running. Would you like to start it?', true);

            if (!shouldStart) {
                throw new SystemError('Ghost instance is not currently running');
            }

            instance.checkEnvironment();
            await this.ui.run(() => instance.start(), 'Starting Ghost');
        }

        await this.ui.run(() => exportTask(this.ui, instance, argv.file), 'Exporting content');
        this.ui.log(`Content exported to ${argv.file}`, 'green');
    }
}

ExportCommand.description = 'Export content from a blog';
ExportCommand.params = 'file';

module.exports = ExportCommand;
<|endoftext|>


<commit_before>/**
 *
 * Scroll to a specific element. You can also append/pass two offset values as parameter
 * to scroll to a specific position.
 *
 * <example>
    :scroll.js
    client
        // scroll to specific element
        .scroll('#myElement')

        // scroll to specific element with offset
        // scroll offset will be added to elements position
        .scroll('#myElement')

        // scroll to specific x and y position
        .scroll(0, 250)
        .end();
 * </example>
 *
 * @param {String=|Number} selector|xoffset element  or x position to scroll to
 * @param {Number}         xoffset|yoffset  x offset or y position to scroll to
 * @param {Number}         yoffset          y offset to scroll to
 *
 * @uses protocol/element, protocol/elementIdLocation, protocol/touchScroll, protocol/execute
 * @type utility
 *
 */

var async = require('async'),
    scrollHelper = require('../helpers/_scroll');

module.exports = function scroll (selector, xoffset, yoffset) {

    /*!
     * make sure that callback contains chainit callback
     */
    var callback = arguments[arguments.length - 1];

    xoffset = typeof xoffset === 'number' ? xoffset : 0;
    yoffset = typeof yoffset === 'number' ? yoffset : 0;

    if(typeof selector === 'number' && typeof xoffset === 'number') {
        yoffset = xoffset;
        xoffset = selector;
        selector = null;
    }

    var self = this,
        response = {};

    if(this.isMobile) {

        async.waterfall([
            function(cb) {

                if(!selector) {
                    return cb();
                }

                self.element(selector, cb);
            },
            function(res) {

                var cb = arguments[arguments.length - 1];

                if(typeof res !== 'function') {
                    selector = res.value.ELEMENT;
                    response.element = res;
                }

                self.touchScroll(selector, xoffset, yoffset, cb);
            },
            function(res, cb) {
                response.touchScroll = res;
                cb();
            }
        ], function(err) {

            callback(err, null, response);

        });

    } else {

        if(selector) {

            async.waterfall([
                function(cb) {
                    self.element(selector, cb);
                },
                function(res, cb) {
                    response.element = res;
                    self.elementIdLocation(res.value.ELEMENT, cb);
                },
                function(res, cb) {
                    response.elementIdLocation = res;
                    self.execute(scrollHelper, res.value.x + xoffset, res.value.y + yoffset, cb);
                },
                function(res, cb) {
                    response.execute = res;
                    cb();
                }
            ], function(err) {

                callback(err, null, response);

            });

        } else {

            async.waterfall([
                function(cb) {
                    self.execute(scrollHelper, xoffset, yoffset, cb);
                },
                function(res, cb) {
                    response.execute = res;
                    cb();
                }
            ], function(err) {
                callback(err, null, response);
            });

        }

    }
};

<commit_msg>fixed command description [ci skip]<commit_after>/**
 *
 * Scroll to a specific element. You can also append/pass two offset values as parameter
 * to scroll to a specific position.
 *
 * <example>
    :scroll.js
    client
        // scroll to specific element
        .scroll('#myElement')

        // scroll to specific element with offset
        // scroll offset will be added to elements position
        .scroll('#myElement')

        // scroll to specific x and y position
        .scroll(0, 250)
        .end();
 * </example>
 *
 * @param {String=}  selector  element to scroll to
 * @param {Number}   xoffset   x offset to scroll to
 * @param {Number}   yoffset   y offset to scroll to
 *
 * @uses protocol/element, protocol/elementIdLocation, protocol/touchScroll, protocol/execute
 * @type utility
 *
 */

var async = require('async'),
    scrollHelper = require('../helpers/_scroll');

module.exports = function scroll (selector, xoffset, yoffset) {

    /*!
     * make sure that callback contains chainit callback
     */
    var callback = arguments[arguments.length - 1];

    xoffset = typeof xoffset === 'number' ? xoffset : 0;
    yoffset = typeof yoffset === 'number' ? yoffset : 0;

    if(typeof selector === 'number' && typeof xoffset === 'number') {
        yoffset = xoffset;
        xoffset = selector;
        selector = null;
    }

    var self = this,
        response = {};

    if(this.isMobile) {

        async.waterfall([
            function(cb) {

                if(!selector) {
                    return cb();
                }

                self.element(selector, cb);
            },
            function(res) {

                var cb = arguments[arguments.length - 1];

                if(typeof res !== 'function') {
                    selector = res.value.ELEMENT;
                    response.element = res;
                }

                self.touchScroll(selector, xoffset, yoffset, cb);
            },
            function(res, cb) {
                response.touchScroll = res;
                cb();
            }
        ], function(err) {

            callback(err, null, response);

        });

    } else {

        if(selector) {

            async.waterfall([
                function(cb) {
                    self.element(selector, cb);
                },
                function(res, cb) {
                    response.element = res;
                    self.elementIdLocation(res.value.ELEMENT, cb);
                },
                function(res, cb) {
                    response.elementIdLocation = res;
                    self.execute(scrollHelper, res.value.x + xoffset, res.value.y + yoffset, cb);
                },
                function(res, cb) {
                    response.execute = res;
                    cb();
                }
            ], function(err) {

                callback(err, null, response);

            });

        } else {

            async.waterfall([
                function(cb) {
                    self.execute(scrollHelper, xoffset, yoffset, cb);
                },
                function(res, cb) {
                    response.execute = res;
                    cb();
                }
            ], function(err) {
                callback(err, null, response);
            });

        }

    }
};

<|endoftext|>


<commit_before>'use strict'

const {Command} = require('heroku-cli-command')
const path = require('path')
const dirs = require('../dirs')
const version = require('../version')
const lock = require('rwlockfile')

class Update extends Command {
  async run () {
    this.fs = require('fs-extra')
    this.got = require('got')
    this.branch = 'v6'
    this.action('heroku-cli: Updating CLI')
    this.manifest = await this.fetchManifest()
    if (this.flags.force || version !== this.manifest.version) {
      this.action(`heroku-cli: Updating CLI to ${this.color.green(this.manifest.version)}${this.branch === 'stable' ? '' : ' (' + this.color.yellow(this.branch) + ')'}`)
      await this.update()
      this.action.done()
    } else this.action.done(`already on latest version: ${version}`)
    this.action('heroku-cli: Updating plugins')
  }

  async fetchManifest () {
    let url = `https://cli-assets.heroku.com/branches/${this.branch}/${process.platform}-${process.arch}`
    let {body: manifest} = await this.got(url, {json: true})
    return manifest
  }

  async update () {
    let url = `https://cli-assets.heroku.com/branches/${this.branch}/${this.base}.tar.gz`
    let stream = await this.got.stream(url)
    let dir = path.join(dirs.data, 'jscli')
    let tmp = path.join(dirs.data, 'jscli_tmp')
    await this.extract(stream, tmp)
    await lock.write(dirs.updatelockfile, {skipOwnPid: true})
    this.fs.removeSync(dir)
    this.fs.renameSync(path.join(tmp, this.base), dir)
  }

  extract (stream, dir) {
    const zlib = require('zlib')
    const tar = require('tar-stream')

    return new Promise(resolve => {
      this.fs.removeSync(dir)
      let extract = tar.extract()
      extract.on('entry', (header, stream, next) => {
        let p = path.join(dir, header.name)
        let opts = {mode: header.mode}
        this.debug(p)
        switch (header.type) {
          case 'directory':
            this.fs.mkdirpSync(p, opts)
            next()
            break
          case 'file':
            stream.pipe(this.fs.createWriteStream(p, opts))
            break
          case 'symlink':
            // ignore symlinks since they will not work on windows
            next()
            break
          default: throw new Error(header.type)
        }
        stream.resume()
        stream.on('end', next)
      })
      extract.on('finish', resolve)
      stream
      .pipe(zlib.createGunzip())
      .pipe(extract)
    })
  }

  get base () {
    return `heroku-v${this.manifest.version}-${process.platform}-${process.arch}`
  }

  static async checkIfUpdating () {
    const lock = require('rwlockfile')
    if (await lock.hasWriter(dirs.updatelockfile)) {
      console.error('heroku-cli: warning: update in process')
      await lock.read(dirs.updatelockfile)
      lock.unreadSync(dirs.updatelockfile)
      const {spawnSync} = require('child_process')
      const {status} = spawnSync('heroku', process.argv.slice(2), {stdio: 'inherit', shell: true})
      process.exit(status)
    } else {
      await lock.read(dirs.updatelockfile)
    }
  }
}

Update.topic = 'update'
Update.flags = [
  {name: 'force', char: 'f', hidden: true}
]

module.exports = Update
<commit_msg>documenting<commit_after>'use strict'

const {Command} = require('heroku-cli-command')
const path = require('path')
const dirs = require('../dirs')
const version = require('../version')
const lock = require('rwlockfile')

class Update extends Command {
  async run () {
    this.fs = require('fs-extra')
    this.got = require('got')
    this.branch = 'v6'
    this.action('heroku-cli: Updating CLI')
    this.manifest = await this.fetchManifest()
    if (this.flags.force || version !== this.manifest.version) {
      this.action(`heroku-cli: Updating CLI to ${this.color.green(this.manifest.version)}${this.branch === 'stable' ? '' : ' (' + this.color.yellow(this.branch) + ')'}`)
      await this.update()
      this.action.done()
    } else this.action.done(`already on latest version: ${version}`)
    this.action('heroku-cli: Updating plugins')
  }

  async fetchManifest () {
    let url = `https://cli-assets.heroku.com/branches/${this.branch}/${process.platform}-${process.arch}`
    let {body: manifest} = await this.got(url, {json: true})
    return manifest
  }

  async update () {
    let url = `https://cli-assets.heroku.com/branches/${this.branch}/${this.base}.tar.gz`
    let stream = await this.got.stream(url)
    let dir = path.join(dirs.data, 'jscli')
    let tmp = path.join(dirs.data, 'jscli_tmp')
    await this.extract(stream, tmp)
    await lock.write(dirs.updatelockfile, {skipOwnPid: true})
    this.fs.removeSync(dir)
    this.fs.renameSync(path.join(tmp, this.base), dir)
  }

  extract (stream, dir) {
    const zlib = require('zlib')
    const tar = require('tar-stream')

    return new Promise(resolve => {
      this.fs.removeSync(dir)
      let extract = tar.extract()
      extract.on('entry', (header, stream, next) => {
        let p = path.join(dir, header.name)
        let opts = {mode: header.mode}
        this.debug(p)
        switch (header.type) {
          case 'directory':
            this.fs.mkdirpSync(p, opts)
            next()
            break
          case 'file':
            stream.pipe(this.fs.createWriteStream(p, opts))
            break
          case 'symlink':
            // ignore symlinks since they will not work on windows
            next()
            break
          default: throw new Error(header.type)
        }
        stream.resume()
        stream.on('end', next)
      })
      extract.on('finish', resolve)
      stream
      .pipe(zlib.createGunzip())
      .pipe(extract)
    })
  }

  get base () {
    return `heroku-v${this.manifest.version}-${process.platform}-${process.arch}`
  }

  /**
   * checks if there is an update running
   * if there is an update running, it waits for it to complete, then restarts the CLI
   * if no update running, checks if an update is needed and fires off an autoupdate process
   */
  static async checkIfUpdating () {
    const lock = require('rwlockfile')
    if (await lock.hasWriter(dirs.updatelockfile)) {
      console.error('heroku-cli: warning: update in process')
      await lock.read(dirs.updatelockfile)
      lock.unreadSync(dirs.updatelockfile)
      const {spawnSync} = require('child_process')
      const {status} = spawnSync('heroku', process.argv.slice(2), {stdio: 'inherit', shell: true})
      process.exit(status)
    } else {
      await lock.read(dirs.updatelockfile)
    }
  }
}

Update.topic = 'update'
Update.flags = [
  {name: 'force', char: 'f', hidden: true}
]

module.exports = Update
<|endoftext|>


<commit_before>/*jshint esversion: 6 */
const Upload = module.exports;
const Util = require("../common-util");
const Pinning = require("./pin-rpc");
const nThen = require("nthen");
const Core = require("./core");

Upload.status = function (Env, safeKey, filesize, _cb) { // FIXME FILES
    var cb = Util.once(Util.mkAsync(_cb));

    // validate that the provided size is actually a positive number
    if (typeof(filesize) !== 'number' &&
        filesize >= 0) { return void cb('E_INVALID_SIZE'); }

    nThen(function (w) {
        // if the proposed upload size is within the regular limit
        // jump ahead to the next block
        if (filesize <= Env.maxUploadSize) { return; }

        // if larger uploads aren't explicitly enabled then reject them
        if (typeof(Env.premiumUploadSize) !== 'number') {
            w.abort();
            return void cb('TOO_LARGE');
        }

        // otherwise go and retrieve info about the user's quota
        Pinning.getLimit(Env, safeKey, w(function (err, limit) {
            if (err) {
                w.abort();
                return void cb("E_BAD_LIMIT");
            }

            var plan = limit[1];

            // see if they have a special plan, reject them if not
            if (plan === '') {
                w.abort();
                return void cb('TOO_LARGE');
            }

            // and that they're not over the greater limit
            if (filesize >= Env.premiumUploadSize) {
                w.abort();
                return void cb("TOO_LARGE");
            }

            // fallthrough will proceed to the next block
        }));
    }).nThen(function (w) {
        var abortAndCB = Util.both(w.abort, cb);
        Env.blobStore.status(safeKey, w(function (err, inProgress) {
            // if there's an error something is weird
            if (err) { return void abortAndCB(err); }

            // we cannot upload two things at once
            if (inProgress) { return void abortAndCB(void 0, true); }
        }));
    }).nThen(function () {
        // if yuo're here then there are no pending uploads
        // check if you have space in your quota to upload something of this size
        Pinning.getFreeSpace(Env, safeKey, function (e, free) {
            if (e) { return void cb(e); }
            if (filesize >= free) { return cb('NOT_ENOUGH_SPACE'); }

            var user = Core.getSession(Env.Sessions, safeKey);
            user.pendingUploadSize = filesize;
            user.currentUploadSize = 0;

            cb(void 0, false);
        });
    });
};

Upload.upload = function (Env, safeKey, chunk, cb) {
    Env.blobStore.upload(safeKey, chunk, cb);
};

Upload.complete = function (Env, safeKey, arg, cb) {
    Env.blobStore.closeBlobstage(safeKey);
    Env.completeUpload(safeKey, arg, false, cb);
};

Upload.cancel = function (Env, safeKey, arg, cb) {
    Env.blobStore.cancel(safeKey, arg, cb);
};

Upload.complete_owned = function (Env, safeKey, arg, cb) {
    Env.blobStore.closeBlobstage(safeKey);
    var user = Core.getSession(Env.Sessions, safeKey);
    var size = user.pendingUploadSize;
    Env.completeUpload(safeKey, arg, true, size, cb);
};

<commit_msg>fix incomplete unowned file upload<commit_after>/*jshint esversion: 6 */
const Upload = module.exports;
const Util = require("../common-util");
const Pinning = require("./pin-rpc");
const nThen = require("nthen");
const Core = require("./core");

Upload.status = function (Env, safeKey, filesize, _cb) { // FIXME FILES
    var cb = Util.once(Util.mkAsync(_cb));

    // validate that the provided size is actually a positive number
    if (typeof(filesize) !== 'number' &&
        filesize >= 0) { return void cb('E_INVALID_SIZE'); }

    nThen(function (w) {
        // if the proposed upload size is within the regular limit
        // jump ahead to the next block
        if (filesize <= Env.maxUploadSize) { return; }

        // if larger uploads aren't explicitly enabled then reject them
        if (typeof(Env.premiumUploadSize) !== 'number') {
            w.abort();
            return void cb('TOO_LARGE');
        }

        // otherwise go and retrieve info about the user's quota
        Pinning.getLimit(Env, safeKey, w(function (err, limit) {
            if (err) {
                w.abort();
                return void cb("E_BAD_LIMIT");
            }

            var plan = limit[1];

            // see if they have a special plan, reject them if not
            if (plan === '') {
                w.abort();
                return void cb('TOO_LARGE');
            }

            // and that they're not over the greater limit
            if (filesize >= Env.premiumUploadSize) {
                w.abort();
                return void cb("TOO_LARGE");
            }

            // fallthrough will proceed to the next block
        }));
    }).nThen(function (w) {
        var abortAndCB = Util.both(w.abort, cb);
        Env.blobStore.status(safeKey, w(function (err, inProgress) {
            // if there's an error something is weird
            if (err) { return void abortAndCB(err); }

            // we cannot upload two things at once
            if (inProgress) { return void abortAndCB(void 0, true); }
        }));
    }).nThen(function () {
        // if yuo're here then there are no pending uploads
        // check if you have space in your quota to upload something of this size
        Pinning.getFreeSpace(Env, safeKey, function (e, free) {
            if (e) { return void cb(e); }
            if (filesize >= free) { return cb('NOT_ENOUGH_SPACE'); }

            var user = Core.getSession(Env.Sessions, safeKey);
            user.pendingUploadSize = filesize;
            user.currentUploadSize = 0;

            cb(void 0, false);
        });
    });
};

Upload.upload = function (Env, safeKey, chunk, cb) {
    Env.blobStore.upload(safeKey, chunk, cb);
};

Upload.cancel = function (Env, safeKey, arg, cb) {
    Env.blobStore.cancel(safeKey, arg, cb);
};

var completeUpload = function (owned) {
    return function (Env, safeKey, arg, cb) {
        Env.blobStore.closeBlobstage(safeKey);
        var user = Core.getSession(Env.Sessions, safeKey);
        var size = user.pendingUploadSize;
        Env.completeUpload(safeKey, arg, Boolean(owned), size, cb);
    };
};

Upload.complete = completeUpload(false);
Upload.complete_owned = completeUpload(true);
<|endoftext|>


<commit_before>var cypher = require('./cypher-utils');
var Concept = require('./concept');

function ConceptManager(db) {
	this.db = db;
};

/*
创建Concept节点
参数
	- cb 回调函数function(err, Concept)
*/
ConceptManager.prototype.create = function (cb) {

	var self = this;

	// 组合查询语句
	var query = [];
	query.push(cypher.create('p', 'Concept'));		// 创建节点
	query.push(cypher.ret('p'));					// 返回刚刚创建的节点

	// 执行查询
	this.db.cypher({
		query: query.join('\n')
	}, function (err, result) {
		if (err) cb(err);
		else cb(null, new Concept(result[0].p._id, self.db));
	});
};

/*
删除Concept节点
参数
	- id 指定删除的节点的id
	- cb 回调函数function(err, result)
*/
ConceptManager.prototype.del = function (id, cb) {

	var self = this;
	var query = [];
	query.push(cypher.match('p', 'Concept'));		// 匹配Concept标签
	query.push(cypher.idFilter('p', id));			// 根据id进行筛选
	query.push(cypher.matchConnect('p','','r'));	// 找出当前节点相关的所有连接
	query.push(cypher.del('r'));					// 删除这些连接
	query.push(cypher.del('p'));					// 删除节点

	console.log(query.join('\n'));

	this.db.cypher({
		query: query.join('\n')
	}, cb);
};

/*
获取节点
参数：
	- id 节点id
	- cb 回调函数function(err, Concept)
*/
ConceptManager.prototype.get = function (id, cb) {
	var db = this.db;
	var query = [];
	query.push(cypher.match('p', 'Concept'));
	query.push(cypher.idFilter('p', id));
	query.push(cypher.ret('p'));
	this.db.cypher({
		query: query.join('\n')
	}, function (err, result) {
		if(err) cb(err);
		else {
			var concept = new Concept(result[0].p._id, db);
			cb(err, concept);
		}
	});
};

/*
根据节点name获取节点
*/
ConceptManager.prototype.findByName = function (name, cb) {
	var db = this.db;
	var query = [];
	query.push('Match (p:Concept)-[:hasName]->(n:Name{text:{name}})');
	query.push(cypher.ret('p'));
	this.db.cypher({
		query: query.join('\n'),
		params: {name: name}
	}, function (err, result) {
		if(err) cb(err);
		else {
			var persons = [];
			result.forEach(function (res) {
				var person = new Concept(res.p._id, db);
				persons.push(person);
			});
			cb(err, persons);
		}
	});
};

module.exports = ConceptManager;<commit_msg>update<commit_after>var cypher = require('./cypher-utils');
var Concept = require('./concept');

function ConceptManager(db) {
	this.db = db;
};

/*
创建Concept节点
参数
	- cb 回调函数function(err, Concept)
*/
ConceptManager.prototype.create = function (cb) {

	var self = this;

	// 组合查询语句
	var query = [];
	query.push(cypher.create('p', 'Concept'));		// 创建节点
	query.push(cypher.ret('p'));					// 返回刚刚创建的节点

	// 执行查询
	this.db.cypher({
		query: query.join('\n')
	}, function (err, result) {
		if (err) cb(err);
		else cb(null, new Concept(result[0].p._id, self.db));
	});
};

/*
删除Concept节点
参数
	- id 指定删除的节点的id
	- cb 回调函数function(err, result)
*/
ConceptManager.prototype.del = function (id, cb) {

	var query = [];
	query.push(cypher.match('p', 'Concept'));		// 匹配Concept标签
	query.push(cypher.idFilter('p', id));			// 根据id进行筛选
	query.push(cypher.matchConnect('p','','r'));	// 找出当前节点相关的所有连接
	query.push(cypher.del('r'));					// 删除这些连接
	query.push(cypher.del('p'));					// 删除节点

	console.log(query.join('\n'));

	this.db.cypher({
		query: query.join('\n')
	}, cb);
};

/*
获取节点
参数：
	- id 节点id
	- cb 回调函数function(err, Concept)
*/
ConceptManager.prototype.get = function (id, cb) {
	var db = this.db;
	var query = [];
	query.push(cypher.match('p', 'Concept'));
	query.push(cypher.idFilter('p', id));
	query.push(cypher.ret('p'));
	this.db.cypher({
		query: query.join('\n')
	}, function (err, result) {
		if(err) cb(err);
		else {
			var concept = new Concept(result[0].p._id, db);
			cb(err, concept);
		}
	});
};

/*
根据节点name获取节点
*/
ConceptManager.prototype.findByName = function (name, cb) {
	var db = this.db;
	var query = [];
	query.push('Match (p:Concept)-[:hasName]->(n:Name{text:{name}})');
	query.push(cypher.ret('p'));
	this.db.cypher({
		query: query.join('\n'),
		params: {name: name}
	}, function (err, result) {
		if(err) cb(err);
		else {
			var persons = [];
			result.forEach(function (res) {
				var person = new Concept(res.p._id, db);
				persons.push(person);
			});
			cb(err, persons);
		}
	});
};

module.exports = ConceptManager;<|endoftext|>