<commit_before>/**
 * Titanium SDK Library for Node.js
 * Copyright (c) 2012 by Appcelerator, Inc. All Rights Reserved.
 * Please see the LICENSE file for information about licensing.
 */
var fs = require('fs'),
	path = require('path'),
	async = require('async'),
	appc = require('node-appc'),
	i18n = appc.i18n(__dirname),
	__ = i18n.__,
	__n = i18n.__n,
	spawn = require('child_process').spawn,
	afs = appc.fs,
	version = appc.version,
	manifest = appc.pkginfo.manifest(module),
	platformAliases = {
		// add additional aliases here for new platforms
		'ipad': 'iphone',
		'ios': 'iphone'
	};

exports.i18n = require('./i18n');
exports.jss = require('./jss');
exports.tiappxml = require('./tiappxml');
exports.legacy = require('./legacy');

exports.manifest = manifest;
exports.availablePlatforms = (manifest.platforms || []).sort();
exports.availablePlatformsNames = (manifest.platforms || []).concat(Object.keys(platformAliases)).sort();

exports.commonOptions = function (logger, config) {
	return {
		sdk: {
			abbr: 's',
			desc: __('Titanium SDK version to use')
		},
		'log-level': {
			callback: function (value) {
				logger.levels[value] && logger.setLevel(value);
			},
			desc: __('minimum logging level'),
			default: config.cli.logLevel || 'warn',
			hint: __('level'),
			values: logger.getLevels()
		}
	};
};

exports.platformOptions = function (logger, config, cli, commandName, finished) {
	var result = {};

	if (!commandName) {
		finished(result);
		return;
	}

	function set(obj, title, platform) {
		// add the platform and title to the options and flags
		['options', 'flags'].forEach(function (type) {
			if (obj[type]) {
				result[platform] || (result[platform] = {
					platform: platform,
					title: title || platform
				});
				result[platform][type] = obj[type];
			}
		});
	}

	// for each platform, fetch their specific flags/options
	async.parallel(manifest.platforms.map(function (platform) {
		return function (callback) {
			var platformDir = path.join(path.dirname(module.filename), '..', '..', '..', platform),
				platformCommand = path.join(platformDir, 'cli', 'commands', '_' + commandName + '.js'),
				command,
				conf,
				title;

			if (!afs.exists(platformCommand)) return callback();

			command = require(platformCommand);
			if (!command || !command.config) return callback();

			// try to get the platform specific configuration
			conf = command.config(logger, config, cli);

			try {
				// try to read a title from the platform's package.json
				title = JSON.parse(fs.readFileSync(path.join(platformDir, 'package.json'))).title;
			} catch (e) {}

			if (typeof conf == 'function') {
				// async callback
				conf(function (obj) {
					set(obj, title, platform);
					callback();
				});
				return;
			}

			set(conf, title, platform);
			callback();
		};
	}), function () {
		finished(result);
	});
};

exports.validateProjectDir = function(logger, cli, argv, name) {
	var dir = argv[name] || (process.env.SOURCE_ROOT ? path.join(process.env.SOURCE_ROOT, '..', '..') : '.'),
		projectDir = argv[name] = appc.fs.resolvePath(dir);

	if (!appc.fs.exists(projectDir)) {
		logger.banner();
		logger.error(__('Project directory does not exist') + '\n');
		process.exit(1);
	}

	var tiapp = path.join(projectDir, 'tiapp.xml');
	while (!appc.fs.exists(tiapp) && tiapp.split(path.sep).length > 2) {
		projectDir = path.dirname(projectDir);
		tiapp = path.join(projectDir, 'tiapp.xml');
	}

	if (tiapp.split(path.sep).length == 2) {
		logger.banner();
		logger.error(__('Invalid project directory "%s"', dir) + '\n');
		dir == '.' && logger.log(__("Use the %s property to specify the project's directory", '--project-dir'.cyan) + '\n');
		process.exit(1);
	}
};

exports.loadPlugins = function (logger, cli, config, projectDir) {
	var tiapp = new exports.tiappxml(path.join(projectDir, 'tiapp.xml'));

	// find all hooks for active plugins
	appc.tiplugin.find(tiapp.plugins, projectDir, config, logger, function (plugins) {
		if (plugins.missing.length) {
			logger.error(__('Could not find all required Titanium plugins:'))
			plugins.missing.forEach(function (m) {
				logger.error('   id: ' + m.id + '\t version: ' + m.version);
			});
			logger.log();
			process.exit(1);
		}

		if (plugins.found.length) {
			plugins.found.forEach(function (plugin) {
				// we don't support plugins that have both a plugin.py and new .js files
				plugin.legacy || cli.scanHooks(afs.resolvePath(plugin.pluginPath, 'hooks'));
			});
		} else {
			logger.debug(__('No project level plugins to load'));
		}
	});

	if (cli.hooks.loadedFilenames.length) {
		// display all hooks for debugging
		logger.debug(__('Loaded plugin hooks:'));
		cli.hooks.loadedFilenames.forEach(function (f) {
			logger.debug(f.cyan);
		});
	}

	if (cli.hooks.incompatibleFilenames.length) {
		// display all hooks for debugging
		logger.debug(__('Incompatible plugin hooks:'));
		cli.hooks.incompatibleFilenames.forEach(function (f) {
			logger.debug(f.cyan);
		});
	}
};

exports.validateCorrectSDK = function (logger, config, cli, projectDir) {
	// tiapp.xml should exist by the time we get here
	var tiappxml = new exports.tiappxml(path.join(projectDir, 'tiapp.xml')),
		sdk = tiappxml['sdk-version'];

	if (!sdk || version.eq(sdk, manifest.version)) return true;

	// check the project's preferred sdk is even installed
	if (sdk == '__global__' || !cli.env.sdks[sdk]) {
		logger.banner();
		logger.error(__("Unable to compile project because the 'sdk-version' in the tiapp.xml is not installed") + '\n');
		logger.log(__("The project's %s is currently set to %s, which is not installed.", 'sdk-version'.cyan, sdk.cyan) + '\n');
		logger.log(__("Update the %s in the tiapp.xml to one of the installed Titaniums SDKs:", 'sdk-version'.cyan));
		Object.keys(cli.env.sdks).sort().forEach(function (ver) {
			if (ver != '__global__') {
				logger.log('    ' + ver.cyan);
			}
		});
		logger.log(__("or run '%s' to download and install Titanium SDK %s", ('titanium sdk install ' + sdk).cyan, sdk) + '\n');
		process.exit(1);
	}

	var args = cli.argv.$_,
		p = args.indexOf('--sdk'),
		platform = platformAliases[cli.argv.platform] || cli.argv.platform,
		cmd = [],
		emulatorCmd = [],
		cmdRoot;

	if (p != -1) {
		args.splice(p, 2);
	}

	if (version.lt(sdk, '2.2.0')) { // technically, there is no 2.2, it was released as 3.0
		cmdRoot = 'python';
		exports.legacy.constructLegacyCommand(cli, tiappxml, platform, cmd, emulatorCmd);
	} else {
		cmdRoot = 'node';
		cmd = cmd.concat(cli.argv.$0.split(' ')[1], cli.argv.$_, '--sdk', sdk);
	}

	// fork or die
	if (config.cli.failOnWrongSDK) {
		logger.banner();
		logger.error(__('Unable to compile a %s project with Titanium SDK %s', version.format(sdk, 3, 3), version.format(manifest.version, 3, 3)) + '\n');
		logger.log(__("Run '%s' to build using the correct Titanium SDK or update the %s in the tiapp.xml to the current Titaniums SDK: %s",
			(cmdRoot + cmd.join(' ')).cyan, 'sdk-version'.cyan, manifest.version.cyan) + '\n');
		process.exit(1);
	}

	if (emulatorCmd.length > 0) {
		// console.log('Forking correct SDK command: ' + ( cmdRoot + ' ' +  emulatorCmd.join(' ') ).cyan + '\n');
		spawn(cmdRoot, emulatorCmd,{});
	}

	// console.log('Forking correct SDK command: ' + ( cmdRoot + ' ' +  cmd.join(' ') ).cyan + '\n');
	spawn(cmdRoot, cmd, {
		stdio: 'inherit'
	});
};

exports.validatePlatformOptions = function (logger, config, cli, commandName) {
	var platform = cli.argv.platform,
		platformCommand = path.join(path.dirname(module.filename), '..', '..', '..', manifest.platforms[manifest.platforms.indexOf(platform)], 'cli', 'commands', '_' + commandName + '.js');

	if (afs.exists(platformCommand)) {
		var command = require(platformCommand),
			result = command && command.validate ? command.validate(logger, config, cli) : null;
		if (result === false) {
			return false;
		}
	}
};

exports.scrubPlatforms = function (platforms) {
	var r = {
		scrubbed: [], // distinct list of un-aliased platforms
		bad: []
	};

	platforms.toLowerCase().split(',').map(function (p) {
		return platformAliases[p] || p;
	}).forEach(function (p) {
		if (manifest.platforms.indexOf(p) == -1) {
			r.bad.push(p);
		} else if (r.scrubbed.indexOf(p) == -1) {
			r.scrubbed.push(p);
		}
	});

	return r;
};

exports.resolvePlatform = function (platform) {
	return platformAliases[platform] || platform;
};

exports.filterPlatforms = function (platform) {
	platform = platformAliases[platform] || platform;
	return exports.availablePlatforms.filter(function (name) {
		return name != platform;
	});
};

exports.validatePlatform = function (logger, argv, name) {
	var platform = name ? argv[name] : argv,
		p = argv[name] = platformAliases[platform] || platform;
	if (!p || manifest.platforms.indexOf(p) == -1) {
		logger.banner();
		logger.error(__('Invalid platform "%s"', platform) + '\n');
		appc.string.suggest(platform, manifest.platforms, logger.log);
		logger.log(__('Available platforms for SDK version %s:', manifest.version));
		manifest.platforms.forEach(function (p) {
			logger.log('    ' + p.cyan);
		});
		logger.log();
		process.exit(1);
	}
};

exports.validatePlatforms = function (logger, platforms) {
	platforms.forEach(function (p) {
		exports.validatePlatform(logger, p);
	});
	return platforms;
};<commit_msg>[TIMOB-11330] Fixed bug with SDK level commands not working when working in a project's subdir.<commit_after>/**
 * Titanium SDK Library for Node.js
 * Copyright (c) 2012 by Appcelerator, Inc. All Rights Reserved.
 * Please see the LICENSE file for information about licensing.
 */
var fs = require('fs'),
	path = require('path'),
	async = require('async'),
	appc = require('node-appc'),
	i18n = appc.i18n(__dirname),
	__ = i18n.__,
	__n = i18n.__n,
	spawn = require('child_process').spawn,
	afs = appc.fs,
	version = appc.version,
	manifest = appc.pkginfo.manifest(module),
	platformAliases = {
		// add additional aliases here for new platforms
		'ipad': 'iphone',
		'ios': 'iphone'
	};

exports.i18n = require('./i18n');
exports.jss = require('./jss');
exports.tiappxml = require('./tiappxml');
exports.legacy = require('./legacy');

exports.manifest = manifest;
exports.availablePlatforms = (manifest.platforms || []).sort();
exports.availablePlatformsNames = (manifest.platforms || []).concat(Object.keys(platformAliases)).sort();

exports.commonOptions = function (logger, config) {
	return {
		sdk: {
			abbr: 's',
			desc: __('Titanium SDK version to use')
		},
		'log-level': {
			callback: function (value) {
				logger.levels[value] && logger.setLevel(value);
			},
			desc: __('minimum logging level'),
			default: config.cli.logLevel || 'warn',
			hint: __('level'),
			values: logger.getLevels()
		}
	};
};

exports.platformOptions = function (logger, config, cli, commandName, finished) {
	var result = {};

	if (!commandName) {
		finished(result);
		return;
	}

	function set(obj, title, platform) {
		// add the platform and title to the options and flags
		['options', 'flags'].forEach(function (type) {
			if (obj[type]) {
				result[platform] || (result[platform] = {
					platform: platform,
					title: title || platform
				});
				result[platform][type] = obj[type];
			}
		});
	}

	// for each platform, fetch their specific flags/options
	async.parallel(manifest.platforms.map(function (platform) {
		return function (callback) {
			var platformDir = path.join(path.dirname(module.filename), '..', '..', '..', platform),
				platformCommand = path.join(platformDir, 'cli', 'commands', '_' + commandName + '.js'),
				command,
				conf,
				title;

			if (!afs.exists(platformCommand)) return callback();

			command = require(platformCommand);
			if (!command || !command.config) return callback();

			// try to get the platform specific configuration
			conf = command.config(logger, config, cli);

			try {
				// try to read a title from the platform's package.json
				title = JSON.parse(fs.readFileSync(path.join(platformDir, 'package.json'))).title;
			} catch (e) {}

			if (typeof conf == 'function') {
				// async callback
				conf(function (obj) {
					set(obj, title, platform);
					callback();
				});
				return;
			}

			set(conf, title, platform);
			callback();
		};
	}), function () {
		finished(result);
	});
};

exports.validateProjectDir = function(logger, cli, argv, name) {
	var dir = argv[name] || (process.env.SOURCE_ROOT ? path.join(process.env.SOURCE_ROOT, '..', '..') : '.'),
		projectDir = argv[name] = appc.fs.resolvePath(dir);

	if (!appc.fs.exists(projectDir)) {
		logger.banner();
		logger.error(__('Project directory does not exist') + '\n');
		process.exit(1);
	}

	var tiapp = path.join(projectDir, 'tiapp.xml');
	while (!appc.fs.exists(tiapp) && tiapp.split(path.sep).length > 2) {
		projectDir = argv[name] = path.dirname(projectDir);
		tiapp = path.join(projectDir, 'tiapp.xml');
	}

	if (tiapp.split(path.sep).length == 2) {
		logger.banner();
		logger.error(__('Invalid project directory "%s"', dir) + '\n');
		dir == '.' && logger.log(__("Use the %s property to specify the project's directory", '--project-dir'.cyan) + '\n');
		process.exit(1);
	}
};

exports.loadPlugins = function (logger, cli, config, projectDir) {
	var tiapp = new exports.tiappxml(path.join(projectDir, 'tiapp.xml'));

	// find all hooks for active plugins
	appc.tiplugin.find(tiapp.plugins, projectDir, config, logger, function (plugins) {
		if (plugins.missing.length) {
			logger.error(__('Could not find all required Titanium plugins:'))
			plugins.missing.forEach(function (m) {
				logger.error('   id: ' + m.id + '\t version: ' + m.version);
			});
			logger.log();
			process.exit(1);
		}

		if (plugins.found.length) {
			plugins.found.forEach(function (plugin) {
				// we don't support plugins that have both a plugin.py and new .js files
				plugin.legacy || cli.scanHooks(afs.resolvePath(plugin.pluginPath, 'hooks'));
			});
		} else {
			logger.debug(__('No project level plugins to load'));
		}
	});

	if (cli.hooks.loadedFilenames.length) {
		// display all hooks for debugging
		logger.debug(__('Loaded plugin hooks:'));
		cli.hooks.loadedFilenames.forEach(function (f) {
			logger.debug(f.cyan);
		});
	}

	if (cli.hooks.incompatibleFilenames.length) {
		// display all hooks for debugging
		logger.debug(__('Incompatible plugin hooks:'));
		cli.hooks.incompatibleFilenames.forEach(function (f) {
			logger.debug(f.cyan);
		});
	}
};

exports.validateCorrectSDK = function (logger, config, cli, projectDir) {
	// tiapp.xml should exist by the time we get here
	var tiappxml = new exports.tiappxml(path.join(projectDir, 'tiapp.xml')),
		sdk = tiappxml['sdk-version'];

	if (!sdk || version.eq(sdk, manifest.version)) return true;

	// check the project's preferred sdk is even installed
	if (sdk == '__global__' || !cli.env.sdks[sdk]) {
		logger.banner();
		logger.error(__("Unable to compile project because the 'sdk-version' in the tiapp.xml is not installed") + '\n');
		logger.log(__("The project's %s is currently set to %s, which is not installed.", 'sdk-version'.cyan, sdk.cyan) + '\n');
		logger.log(__("Update the %s in the tiapp.xml to one of the installed Titaniums SDKs:", 'sdk-version'.cyan));
		Object.keys(cli.env.sdks).sort().forEach(function (ver) {
			if (ver != '__global__') {
				logger.log('    ' + ver.cyan);
			}
		});
		logger.log(__("or run '%s' to download and install Titanium SDK %s", ('titanium sdk install ' + sdk).cyan, sdk) + '\n');
		process.exit(1);
	}

	var args = cli.argv.$_,
		p = args.indexOf('--sdk'),
		platform = platformAliases[cli.argv.platform] || cli.argv.platform,
		cmd = [],
		emulatorCmd = [],
		cmdRoot;

	if (p != -1) {
		args.splice(p, 2);
	}

	if (version.lt(sdk, '2.2.0')) { // technically, there is no 2.2, it was released as 3.0
		cmdRoot = 'python';
		exports.legacy.constructLegacyCommand(cli, tiappxml, platform, cmd, emulatorCmd);
	} else {
		cmdRoot = 'node';
		cmd = cmd.concat(cli.argv.$0.split(' ')[1], cli.argv.$_, '--sdk', sdk);
	}

	// fork or die
	if (config.cli.failOnWrongSDK) {
		logger.banner();
		logger.error(__('Unable to compile a %s project with Titanium SDK %s', version.format(sdk, 3, 3), version.format(manifest.version, 3, 3)) + '\n');
		logger.log(__("Run '%s' to build using the correct Titanium SDK or update the %s in the tiapp.xml to the current Titaniums SDK: %s",
			(cmdRoot + cmd.join(' ')).cyan, 'sdk-version'.cyan, manifest.version.cyan) + '\n');
		process.exit(1);
	}

	if (emulatorCmd.length > 0) {
		// console.log('Forking correct SDK command: ' + ( cmdRoot + ' ' +  emulatorCmd.join(' ') ).cyan + '\n');
		spawn(cmdRoot, emulatorCmd,{});
	}

	// console.log('Forking correct SDK command: ' + ( cmdRoot + ' ' +  cmd.join(' ') ).cyan + '\n');
	spawn(cmdRoot, cmd, {
		stdio: 'inherit'
	});
};

exports.validatePlatformOptions = function (logger, config, cli, commandName) {
	var platform = cli.argv.platform,
		platformCommand = path.join(path.dirname(module.filename), '..', '..', '..', manifest.platforms[manifest.platforms.indexOf(platform)], 'cli', 'commands', '_' + commandName + '.js');

	if (afs.exists(platformCommand)) {
		var command = require(platformCommand),
			result = command && command.validate ? command.validate(logger, config, cli) : null;
		if (result === false) {
			return false;
		}
	}
};

exports.scrubPlatforms = function (platforms) {
	var r = {
		scrubbed: [], // distinct list of un-aliased platforms
		bad: []
	};

	platforms.toLowerCase().split(',').map(function (p) {
		return platformAliases[p] || p;
	}).forEach(function (p) {
		if (manifest.platforms.indexOf(p) == -1) {
			r.bad.push(p);
		} else if (r.scrubbed.indexOf(p) == -1) {
			r.scrubbed.push(p);
		}
	});

	return r;
};

exports.resolvePlatform = function (platform) {
	return platformAliases[platform] || platform;
};

exports.filterPlatforms = function (platform) {
	platform = platformAliases[platform] || platform;
	return exports.availablePlatforms.filter(function (name) {
		return name != platform;
	});
};

exports.validatePlatform = function (logger, argv, name) {
	var platform = name ? argv[name] : argv,
		p = argv[name] = platformAliases[platform] || platform;
	if (!p || manifest.platforms.indexOf(p) == -1) {
		logger.banner();
		logger.error(__('Invalid platform "%s"', platform) + '\n');
		appc.string.suggest(platform, manifest.platforms, logger.log);
		logger.log(__('Available platforms for SDK version %s:', manifest.version));
		manifest.platforms.forEach(function (p) {
			logger.log('    ' + p.cyan);
		});
		logger.log();
		process.exit(1);
	}
};

exports.validatePlatforms = function (logger, platforms) {
	platforms.forEach(function (p) {
		exports.validatePlatform(logger, p);
	});
	return platforms;
};<|endoftext|>


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

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

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

import SelectMode from '../_statics/SelectMode';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';
import TreeCalculation from '../_vendors/TreeCalculation';
import ComponentUtil from '../_vendors/ComponentUtil';

class TreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Dropdown.Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

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

    }

    closePopup = () => {
        this.refs.dropdown && this.refs.dropdown.closePopup();
    };

    getTriggerValue = (props = this.props) => {

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

        if (triggerRenderer) {
            return typeof triggerRenderer === 'function' ? triggerRenderer(value, path) : triggerRenderer;
        }

        if (!value) {
            return placeholder;
        }

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

        let result = [];

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

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

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

        addNode(data, -1);

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

                result.push(

                );

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

            }
        }

        return result;

    };

    nodeSelectHandler = (value, path) => {

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

        this.setState({
            path
        });

    };

    changeHandler = value => {

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

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

    };

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

    filterChangeHandler = filter => {
        this.setState({
            filter
        });
    };

    isEmpty = (filter = this.state.filter, data = this.props.data) => {

        if (!filter) {
            return data.length < 1;
        }

        const {displayField} = this.props;
        let result = true;

        Util.preOrderTraverse(data, node => {
            if (node && !!node[displayField]
                && node[displayField].toString().toUpperCase().includes(filter.toUpperCase())) {
                result = false;
                return false;
            }
        });

        return result;

    };

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {

                className, triggerClassName, popupClassName, style, name, data, popupTheme, renderer,
                selectMode, valueField, displayField, descriptionField, triggerRenderer,
                useFilter, isSelectRecursive, allowCollapse, onNodeClick, popupChildren, noMatchedMsg,
                collapsedIconCls, expandedIconCls, radioUncheckedIconCls, radioCheckedIconCls,
                checkboxUncheckedIconCls, checkboxCheckedIconCls, checkboxIndeterminateIconCls,

                ...restProps

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

            isEmpty = this.isEmpty(),

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

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

        return (

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

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

                        {
                            useFilter ?
                                <TextField className="tree-select-filter"
                                           value={filter}
                                           rightIconCls="fas fa-search"
                                           onChange={this.filterChangeHandler}/>
                                :
                                null
                        }

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

                        {
                            useFilter ?

                                :
                                null
                        }

                        {
                            isEmpty ?

                                    {
                                        noMatchedMsg ?
                                            noMatchedMsg
                                            :

                                                No matched value.

                                    }

                                :
                                <Tree className="tree-select-list"
                                      theme={popupTheme}
                                      selectMode={selectMode}
                                      data={data}
                                      filter={filter}
                                      value={value}
                                      valueField={valueField}
                                      displayField={displayField}
                                      descriptionField={descriptionField}
                                      isSelectRecursive={isSelectRecursive}
                                      allowCollapse={allowCollapse}
                                      collapsedIconCls={collapsedIconCls}
                                      expandedIconCls={expandedIconCls}
                                      radioUncheckedIconCls={radioUncheckedIconCls}
                                      radioCheckedIconCls={radioCheckedIconCls}
                                      checkboxUncheckedIconCls={checkboxUncheckedIconCls}
                                      checkboxCheckedIconCls={checkboxCheckedIconCls}
                                      checkboxIndeterminateIconCls={checkboxIndeterminateIconCls}
                                      renderer={renderer}
                                      onNodeClick={onNodeClick}
                                      onNodeSelect={this.nodeSelectHandler}
                                      onChange={this.changeHandler}/>
                        }

                    {popupChildren}

                </Dropdown>

        );

    }
}

TreeSelect.propTypes = {

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

    /**
     * The CSS class name of the trigger element.
     */
    triggerClassName: PropTypes.string,

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

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

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

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

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

    position: PropTypes.oneOf(Util.enumerateValue(Dropdown.Position)),

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

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

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

    title: PropTypes.string,
    triggerValue: PropTypes.string,
    rightIconCls: PropTypes.string,

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

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

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

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

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

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

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

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

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

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

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

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

        children: PropTypes.array,

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

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

    }),

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

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

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

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

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

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

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

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

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

    useFilter: PropTypes.bool,
    noMatchedMsg: PropTypes.string,
    shouldPreventContainerScroll: PropTypes.bool,
    isSelectRecursive: PropTypes.bool,
    allowCollapse: PropTypes.bool,
    collapsedIconCls: PropTypes.string,
    expandedIconCls: PropTypes.string,
    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    popupChildren: PropTypes.any,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

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

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

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

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

};

TreeSelect.defaultProps = {

    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    position: Dropdown.Position.LEFT,
    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,

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

    autoClose: true,
    useFilter: false,

    shouldPreventContainerScroll: true,
    isSelectRecursive: false,
    allowCollapse: true

};

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

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

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

import SelectMode from '../_statics/SelectMode';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';
import TreeCalculation from '../_vendors/TreeCalculation';
import ComponentUtil from '../_vendors/ComponentUtil';

class TreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Dropdown.Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

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

    }

    closePopup = () => {
        this.refs.dropdown && this.refs.dropdown.closePopup();
    };

    getTriggerValue = (props = this.props) => {

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

        if (triggerRenderer) {
            return typeof triggerRenderer === 'function' ? triggerRenderer(value, path) : triggerRenderer;
        }

        if (!value) {
            return placeholder;
        }

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

        let result = [];

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

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

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

        addNode(data, -1);

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

                result.push(

                );

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

            }
        }

        return result;

    };

    nodeSelectHandler = (value, path) => {

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

        this.setState({
            path
        });

    };

    changeHandler = value => {

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

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

    };

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

    filterChangeHandler = filter => {
        this.setState({
            filter
        }, () => {
            const el = this.refs.dropdown;
            el && el.resetPopupPosition();
        });
    };

    isEmpty = (filter = this.state.filter, data = this.props.data) => {

        if (!filter) {
            return data.length < 1;
        }

        const {displayField} = this.props;
        let result = true;

        Util.preOrderTraverse(data, node => {
            if (node && !!node[displayField]
                && node[displayField].toString().toUpperCase().includes(filter.toUpperCase())) {
                result = false;
                return false;
            }
        });

        return result;

    };

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {

                className, triggerClassName, popupClassName, style, name, data, popupTheme, renderer,
                selectMode, valueField, displayField, descriptionField, triggerRenderer,
                useFilter, isSelectRecursive, allowCollapse, onNodeClick, popupChildren, noMatchedMsg,
                collapsedIconCls, expandedIconCls, radioUncheckedIconCls, radioCheckedIconCls,
                checkboxUncheckedIconCls, checkboxCheckedIconCls, checkboxIndeterminateIconCls,

                ...restProps

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

            isEmpty = this.isEmpty(),

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

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

        return (

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

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

                        {
                            useFilter ?
                                <TextField className="tree-select-filter"
                                           value={filter}
                                           rightIconCls="fas fa-search"
                                           onChange={this.filterChangeHandler}/>
                                :
                                null
                        }

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

                        {
                            useFilter ?

                                :
                                null
                        }

                        {
                            isEmpty ?

                                    {
                                        noMatchedMsg ?
                                            noMatchedMsg
                                            :

                                                No matched value.

                                    }

                                :
                                <Tree className="tree-select-list"
                                      theme={popupTheme}
                                      selectMode={selectMode}
                                      data={data}
                                      filter={filter}
                                      value={value}
                                      valueField={valueField}
                                      displayField={displayField}
                                      descriptionField={descriptionField}
                                      isSelectRecursive={isSelectRecursive}
                                      allowCollapse={allowCollapse}
                                      collapsedIconCls={collapsedIconCls}
                                      expandedIconCls={expandedIconCls}
                                      radioUncheckedIconCls={radioUncheckedIconCls}
                                      radioCheckedIconCls={radioCheckedIconCls}
                                      checkboxUncheckedIconCls={checkboxUncheckedIconCls}
                                      checkboxCheckedIconCls={checkboxCheckedIconCls}
                                      checkboxIndeterminateIconCls={checkboxIndeterminateIconCls}
                                      renderer={renderer}
                                      onNodeClick={onNodeClick}
                                      onNodeSelect={this.nodeSelectHandler}
                                      onChange={this.changeHandler}/>
                        }

                    {popupChildren}

                </Dropdown>

        );

    }
}

TreeSelect.propTypes = {

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

    /**
     * The CSS class name of the trigger element.
     */
    triggerClassName: PropTypes.string,

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

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

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

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

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

    position: PropTypes.oneOf(Util.enumerateValue(Dropdown.Position)),

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

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

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

    title: PropTypes.string,
    triggerValue: PropTypes.string,
    rightIconCls: PropTypes.string,

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

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

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

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

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

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

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

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

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

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

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

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

        children: PropTypes.array,

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

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

    }),

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

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

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

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

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

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

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

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

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

    useFilter: PropTypes.bool,
    noMatchedMsg: PropTypes.string,
    shouldPreventContainerScroll: PropTypes.bool,
    isSelectRecursive: PropTypes.bool,
    allowCollapse: PropTypes.bool,
    collapsedIconCls: PropTypes.string,
    expandedIconCls: PropTypes.string,
    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    popupChildren: PropTypes.any,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

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

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

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

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

};

TreeSelect.defaultProps = {

    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    position: Dropdown.Position.LEFT,
    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,

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

    autoClose: true,
    useFilter: false,

    shouldPreventContainerScroll: true,
    isSelectRecursive: false,
    allowCollapse: true

};

export default TreeSelect;<|endoftext|>


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

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

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

import SelectMode from '../_statics/SelectMode';
import VirtualRoot from '../_statics/VirtualRoot';
import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';
import TreeCalculation from '../_vendors/TreeCalculation';
import ComponentUtil from '../_vendors/ComponentUtil';

class TreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

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

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.refs.dropdown && this.refs.dropdown.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.refs.dropdown && this.refs.dropdown.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.refs.dropdown && this.refs.dropdown.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.refs.dropdown && this.refs.dropdown.resetPosition();
    };

    /**
     * public
     */
    openPopup = () => {
        this.refs.dropdown && this.refs.dropdown.openPopup();
    };

    /**
     * public
     */
    closePopup = () => {
        this.refs.dropdown && this.refs.dropdown.closePopup();
    };

    getTriggerValue = (props = this.props) => {

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

        if (triggerRenderer) {
            return typeof triggerRenderer === 'function' ? triggerRenderer(value, path) : triggerRenderer;
        }

        if (!value) {
            return placeholder;
        }

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

        let result = [];

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

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

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

        addNode(data, -1);

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

                result.push(

                );

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

            }
        }

        return result;

    };

    nodeSelectHandler = (value, path) => {

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

        this.setState({
            path
        });

    };

    changeHandler = value => {

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

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

    };

    popupOpenHandler = e => {

        const {useFilter, onOpenPopup} = this.props;

        if (useFilter) {
            this.refs.filter && this.refs.filter.focus();
        }

        onOpenPopup && onOpenPopup(e);

    };

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

    filterChangeHandler = filter => {
        this.setState({
            filter
        }, () => {
            const el = this.refs.dropdown;
            el && el.resetPopupPosition();
        });
    };

    isEmpty = (filter = this.state.filter, data = this.props.data) => {

        if (!filter) {
            return !data;
        }

        const {displayField} = this.props;
        let result = true;

        Util.preOrderTraverse(isArray(data) ? {[VirtualRoot]: true, children: data} : data, node => {
            if (node && !!node[displayField]
                && node[displayField].toString().toUpperCase().includes(filter.toUpperCase())) {
                return result = false;
            }
        });

        return result;

    };

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {

                className, triggerClassName, popupClassName, style, name, data, popupTheme, renderer,
                selectMode, valueField, displayField, descriptionField, triggerRenderer,
                useFilter, filterIconCls, isSelectRecursive, allowCollapse, onNodeClick, popupChildren, noMatchedMsg,
                collapsedIconCls, expandedIconCls, radioUncheckedIconCls, radioCheckedIconCls,
                checkboxUncheckedIconCls, checkboxCheckedIconCls, checkboxIndeterminateIconCls,

                ...restProps

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

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

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

        return (

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

                <Dropdown {...restProps}
                          ref="dropdown"
                          triggerClassName={selectTriggerClassName}
                          popupClassName={selectPopupClassName}
                          popupTheme={popupTheme}
                          triggerValue={this.getTriggerValue()}
                          onOpenPopup={this.popupOpenHandler}
                          onClosePopup={this.popupClosedHandler}>

                        {
                            useFilter ?
                                <TextField ref="filter"
                                           className="tree-select-filter"
                                           value={filter}
                                           rightIconCls={filterIconCls}
                                           onChange={this.filterChangeHandler}/>
                                :
                                null
                        }

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

                        {
                            useFilter ?

                                :
                                null
                        }

                        {
                            this.isEmpty() ?

                                    {
                                        noMatchedMsg ?
                                            noMatchedMsg
                                            :

                                                No matched value.

                                    }

                                :
                                <Tree className="tree-select-list"
                                      theme={popupTheme}
                                      selectMode={selectMode}
                                      data={data}
                                      filter={filter}
                                      value={value}
                                      valueField={valueField}
                                      displayField={displayField}
                                      descriptionField={descriptionField}
                                      isSelectRecursive={isSelectRecursive}
                                      allowCollapse={allowCollapse}
                                      collapsedIconCls={collapsedIconCls}
                                      expandedIconCls={expandedIconCls}
                                      radioUncheckedIconCls={radioUncheckedIconCls}
                                      radioCheckedIconCls={radioCheckedIconCls}
                                      checkboxUncheckedIconCls={checkboxUncheckedIconCls}
                                      checkboxCheckedIconCls={checkboxCheckedIconCls}
                                      checkboxIndeterminateIconCls={checkboxIndeterminateIconCls}
                                      renderer={renderer}
                                      onNodeClick={onNodeClick}
                                      onNodeSelect={this.nodeSelectHandler}
                                      onChange={this.changeHandler}/>
                        }

                    {popupChildren}

                </Dropdown>

        );

    }
}

TreeSelect.propTypes = {

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

    /**
     * The CSS class name of the trigger element.
     */
    triggerClassName: PropTypes.string,

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

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

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

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

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

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

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

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

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

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),
    triggerValue: PropTypes.string,
    rightIconCls: PropTypes.string,

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

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

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

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

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

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

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

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

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

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

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

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

        children: PropTypes.array,

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

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

    }), PropTypes.array]),

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

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

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

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

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

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

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

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

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

    useFilter: PropTypes.bool,
    filterIconCls: PropTypes.string,
    noMatchedMsg: PropTypes.string,
    shouldPreventContainerScroll: PropTypes.bool,
    isSelectRecursive: PropTypes.bool,
    allowCollapse: PropTypes.bool,
    collapsedIconCls: PropTypes.string,
    expandedIconCls: PropTypes.string,
    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    popupChildren: PropTypes.any,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

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

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

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

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

};

TreeSelect.defaultProps = {

    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,
    tipPosition: Position.BOTTOM,

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

    autoClose: true,
    useFilter: false,
    filterIconCls: 'fas fa-search',

    shouldPreventContainerScroll: true,
    isSelectRecursive: false,
    allowCollapse: true

};

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

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

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

import SelectMode from '../_statics/SelectMode';
import VirtualRoot from '../_statics/VirtualRoot';
import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import Event from '../_vendors/Event';
import TreeCalculation from '../_vendors/TreeCalculation';
import ComponentUtil from '../_vendors/ComponentUtil';

class TreeSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

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

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.refs.dropdown && this.refs.dropdown.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.refs.dropdown && this.refs.dropdown.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.refs.dropdown && this.refs.dropdown.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.refs.dropdown && this.refs.dropdown.resetPosition();
    };

    /**
     * public
     */
    openPopup = () => {
        this.refs.dropdown && this.refs.dropdown.openPopup();
    };

    /**
     * public
     */
    closePopup = () => {
        this.refs.dropdown && this.refs.dropdown.closePopup();
    };

    getTriggerValue = (props = this.props) => {

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

        if (triggerRenderer) {
            return typeof triggerRenderer === 'function' ? triggerRenderer(value, path) : triggerRenderer;
        }

        if (!value) {
            return placeholder;
        }

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

        let result = [];

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

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

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

        addNode(data, -1);

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

                result.push(

                );

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

            }
        }

        return result;

    };

    nodeSelectHandler = (value, path) => {

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

        this.setState({
            path
        });

    };

    changeHandler = value => {

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

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

    };

    popupOpenHandler = e => {

        const {useFilter, onOpenPopup} = this.props;

        if (useFilter) {
            this.refs.filter && this.refs.filter.focus();
        }

        onOpenPopup && onOpenPopup(e);

    };

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

    filterChangeHandler = filter => {
        this.setState({
            filter
        }, () => {
            const el = this.refs.dropdown;
            el && el.resetPopupPosition();
        });
    };

    isEmpty = (filter = this.state.filter, data = this.props.data) => {

        if (!filter) {
            return !data;
        }

        const {displayField} = this.props;
        let result = true;

        Util.preOrderTraverse(isArray(data) ? {[VirtualRoot]: true, children: data} : data, node => {
            if (node && !!node[displayField]
                && node[displayField].toString().toUpperCase().includes(filter.toUpperCase())) {
                return result = false;
            }
        });

        return result;

    };

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {

                className, triggerClassName, popupClassName, style, name, data, popupTheme, renderer,
                selectMode, valueField, displayField, descriptionField, triggerRenderer,
                useFilter, filterIconCls, isSelectRecursive, allowCollapse, onNodeClick, popupChildren, noMatchedMsg,
                collapsedIconCls, expandedIconCls, radioUncheckedIconCls, radioCheckedIconCls,
                checkboxUncheckedIconCls, checkboxCheckedIconCls, checkboxIndeterminateIconCls,

                ...restProps

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

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

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

        return (

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

                <Dropdown {...restProps}
                          ref="dropdown"
                          triggerClassName={selectTriggerClassName}
                          popupClassName={selectPopupClassName}
                          popupTheme={popupTheme}
                          triggerValue={this.getTriggerValue()}
                          onOpenPopup={this.popupOpenHandler}
                          onClosePopup={this.popupClosedHandler}>

                        {
                            useFilter ?
                                <TextField ref="filter"
                                           className="tree-select-filter"
                                           value={filter}
                                           rightIconCls={filterIconCls}
                                           onChange={this.filterChangeHandler}/>
                                :
                                null
                        }

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

                        {
                            useFilter ?

                                :
                                null
                        }

                        {
                            this.isEmpty() ?

                                    {
                                        noMatchedMsg ?
                                            noMatchedMsg
                                            :

                                                No matched value.

                                    }

                                :
                                <Tree className="tree-select-list"
                                      theme={popupTheme}
                                      selectMode={selectMode}
                                      data={data}
                                      filter={filter}
                                      value={value}
                                      valueField={valueField}
                                      displayField={displayField}
                                      descriptionField={descriptionField}
                                      isSelectRecursive={isSelectRecursive}
                                      allowCollapse={allowCollapse}
                                      collapsedIconCls={collapsedIconCls}
                                      expandedIconCls={expandedIconCls}
                                      radioUncheckedIconCls={radioUncheckedIconCls}
                                      radioCheckedIconCls={radioCheckedIconCls}
                                      checkboxUncheckedIconCls={checkboxUncheckedIconCls}
                                      checkboxCheckedIconCls={checkboxCheckedIconCls}
                                      checkboxIndeterminateIconCls={checkboxIndeterminateIconCls}
                                      renderer={renderer}
                                      onNodeClick={onNodeClick}
                                      onNodeSelect={this.nodeSelectHandler}
                                      onChange={this.changeHandler}/>
                        }

                    {popupChildren}

                </Dropdown>

        );

    }
}

TreeSelect.propTypes = {

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

    /**
     * The CSS class name of the trigger element.
     */
    triggerClassName: PropTypes.string,

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

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

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

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

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

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

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

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

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

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),
    triggerValue: PropTypes.string,
    rightIconCls: PropTypes.string,

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

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

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

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

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

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

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

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

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

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

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

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

        children: PropTypes.array,

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

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

    }), PropTypes.array]),

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

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

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

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

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

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

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

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

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

    useFilter: PropTypes.bool,
    filterIconCls: PropTypes.string,
    noMatchedMsg: PropTypes.string,
    shouldPreventContainerScroll: PropTypes.bool,
    isSelectRecursive: PropTypes.bool,
    allowCollapse: PropTypes.bool,
    collapsedIconCls: PropTypes.string,
    expandedIconCls: PropTypes.string,
    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    popupChildren: PropTypes.any,

    resetPopPositionWait: PropTypes.number,

    renderer: PropTypes.func,

    triggerRenderer: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.func]),

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

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

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

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

};

TreeSelect.defaultProps = {

    theme: Theme.DEFAULT,
    popupTheme: Theme.DEFAULT,

    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    disabled: false,
    selectMode: SelectMode.SINGLE_SELECT,
    tipPosition: Position.BOTTOM,

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

    autoClose: true,
    useFilter: false,
    filterIconCls: 'fas fa-search',

    shouldPreventContainerScroll: true,
    isSelectRecursive: false,
    allowCollapse: true,
    resetPopPositionWait: 250

};

export default TreeSelect;
<|endoftext|>


<commit_before>/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Definitions for all the extensions over the
 *  W3C's event specification by IE in JScript. This file depends on
 *  w3c_event.js.
 *
 * @see http://msdn.microsoft.com/en-us/library/ms535863.aspx
 * @externs
 */

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

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

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

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

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

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

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

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

/**
 * @see http://msdn.microsoft.com/en-us/library/ms535220.aspx
 * @type {(ClipboardData|undefined)}
 */
Event.prototype.clipboardData;

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

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

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

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

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

Event.prototype.domain;

/** @type {Element} */
Event.prototype.fromElement;

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

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

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

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

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

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

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

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

/** @type {Object.<*,*>} */
Event.prototype.recordset;

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

/** @type {(boolean|string|undefined)} */
Event.prototype.returnValue;

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

Event.prototype.scheme;

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

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

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

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

/** @type {Window} */
Event.prototype.source;

/** @type {Element} */
Event.prototype.srcElement;

Event.prototype.srcFilter;

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

/** @type {Element} */
Event.prototype.toElement;

Event.prototype.userName;

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

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

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

/**
 * @constructor
 * @see http://msdn.microsoft.com/en-us/library/windows/apps/hh441257.aspx
 */
function MSPointerPoint() {}

/** @type {number} */
MSPointerPoint.prototype.pointerId;

/** @type {number} */
MSPointerPoint.prototype.pointerType;

/**
 * @constructor
 * @extends {Event}
 * @see http://msdn.microsoft.com/en-us/library/windows/apps/hh441233.aspx
 */
function MSPointerEvent() {}

/** @type {number} */
MSPointerEvent.MSPOINTER_TYPE_MOUSE;

/** @type {number} */
MSPointerEvent.MSPOINTER_TYPE_PEN;

/** @type {number} */
MSPointerEvent.MSPOINTER_TYPE_TOUCH;

/**
 * @return {Array.<MSPointerPoint>}
 */
MSPointerEvent.prototype.getPointerList;

/** @type {number} */
MSPointerEvent.prototype.pointerId;

/** @type {number} */
MSPointerEvent.prototype.pointerType;

<commit_msg><commit_after>/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * @fileoverview Definitions for all the extensions over the
 *  W3C's event specification by IE in JScript. This file depends on
 *  w3c_event.js.
 *
 * @see http://msdn.microsoft.com/en-us/library/ms535863.aspx
 * @externs
 */

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

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

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

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

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

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

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

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

/**
 * @see http://msdn.microsoft.com/en-us/library/ms535220.aspx
 * @type {(ClipboardData|undefined)}
 */
Event.prototype.clipboardData;

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

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

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

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

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

Event.prototype.domain;

/** @type {Element} */
Event.prototype.fromElement;

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

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

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

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

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

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

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

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

/** @type {Object.<*,*>} */
Event.prototype.recordset;

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

/** @type {(boolean|string|undefined)} */
Event.prototype.returnValue;

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

Event.prototype.scheme;

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

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

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

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

/** @type {Window} */
Event.prototype.source;

/** @type {Element} */
Event.prototype.srcElement;

Event.prototype.srcFilter;

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

/** @type {Element} */
Event.prototype.toElement;

Event.prototype.userName;

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

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

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

/**
 * @constructor
 * @see http://msdn.microsoft.com/en-us/library/windows/apps/hh441257.aspx
 */
function MSPointerPoint() {}

/** @type {number} */
MSPointerPoint.prototype.pointerId;

/** @type {number} */
MSPointerPoint.prototype.pointerType;

/**
 * @constructor
 * @extends {Event}
 * @see http://msdn.microsoft.com/en-us/library/windows/apps/hh441233.aspx
 */
function MSPointerEvent() {}

/** @type {number} */
MSPointerEvent.MSPOINTER_TYPE_MOUSE;

/** @type {number} */
MSPointerEvent.MSPOINTER_TYPE_PEN;

/** @type {number} */
MSPointerEvent.MSPOINTER_TYPE_TOUCH;

/** @type {number} */
MSPointerEvent.prototype.pointerId;

/** @type {number} */
MSPointerEvent.prototype.pointerType;
<|endoftext|>