From 59dd1d9ea056425be757a0137e5731458ae68523 Mon Sep 17 00:00:00 2001
From: Jed Watson
Date: Fri, 5 Sep 2014 17:17:29 +1000
Subject: [PATCH 01/31] Publishing examples to gh-pages
---
LICENSE | 21 --
README.md | 49 ---
.../public/build => build}/app-bundle.js | 0
{examples/public/build => build}/example.css | 0
.../public/build => build}/global-bundle.js | 0
.../public/build => build}/select-bundle.js | 0
dist/default.css | 118 -------
examples/src/app.js | 28 --
examples/src/example.less | 104 ------
gulpfile.js | 111 -------
examples/public/index.html => index.html | 0
less/default.less | 46 ---
less/select-control.less | 102 ------
less/select-menu.less | 62 ----
less/select.less | 34 --
lib/select.js | 313 ------------------
package.json | 37 ---
17 files changed, 1025 deletions(-)
delete mode 100644 LICENSE
delete mode 100644 README.md
rename {examples/public/build => build}/app-bundle.js (100%)
rename {examples/public/build => build}/example.css (100%)
rename {examples/public/build => build}/global-bundle.js (100%)
rename {examples/public/build => build}/select-bundle.js (100%)
delete mode 100644 dist/default.css
delete mode 100644 examples/src/app.js
delete mode 100644 examples/src/example.less
delete mode 100644 gulpfile.js
rename examples/public/index.html => index.html (100%)
delete mode 100644 less/default.less
delete mode 100644 less/select-control.less
delete mode 100644 less/select-menu.less
delete mode 100644 less/select.less
delete mode 100644 lib/select.js
delete mode 100644 package.json
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 7862e5a65f..0000000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Jed Watson
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/README.md b/README.md
deleted file mode 100644
index 5be332b466..0000000000
--- a/README.md
+++ /dev/null
@@ -1,49 +0,0 @@
-React-Select
-============
-
-A Select control built with and for [React](http://facebook.github.io/react/index.html), initially being developed for use in [KeystoneJS](http://www.keystonejs.com).
-
-## Project Status
-
-This is currently a work in progress.
-
-It's loosely based on [Selectize](http://brianreavis.github.io/selectize.js/) (in terms of behaviour and user expereience) and [React-Autocomplete](https://github.com/rackt/react-autocomplete) (as a native React Combobox implemenation), as well as other select controls including [Chosen](http://harvesthq.github.io/chosen/) and [Select2](http://ivaynberg.github.io/select2/).
-
-TODO:
-
-- CSS Styles and theme support
-- Multiselect
-- Remote options loading
-- Custom options rendering
-- Cleanup of focus state management
-
-## Installation
-
-You currently need to install this component via NPM and include it in your own React build process (using [Browserify](http://browserify.org), etc).
-
-Standalone builds will be available in the future.
-
-```
-npm install react-select --save
-```
-
-## Usage
-
-React-Select generates a hidden text field containing the selected value, so you can submit it as part of a standard form.
-
-Options should be provided as an `Array` of `Object`s, each with a `value` and `label` property for rendering and searching.
-
-```
-var Select = require('react-select');
-
-var options = [
- { value: 'one', label: 'One' },
- { value: 'two', label: 'Two' }
-];
-
-
-```
diff --git a/examples/public/build/app-bundle.js b/build/app-bundle.js
similarity index 100%
rename from examples/public/build/app-bundle.js
rename to build/app-bundle.js
diff --git a/examples/public/build/example.css b/build/example.css
similarity index 100%
rename from examples/public/build/example.css
rename to build/example.css
diff --git a/examples/public/build/global-bundle.js b/build/global-bundle.js
similarity index 100%
rename from examples/public/build/global-bundle.js
rename to build/global-bundle.js
diff --git a/examples/public/build/select-bundle.js b/build/select-bundle.js
similarity index 100%
rename from examples/public/build/select-bundle.js
rename to build/select-bundle.js
diff --git a/dist/default.css b/dist/default.css
deleted file mode 100644
index af9bb45ea2..0000000000
--- a/dist/default.css
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * React Select
- * ============
- * Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
- * https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
- * MIT License: https://github.com/keystonejs/react-select
-*/
-.Select-control {
- background-color: white;
- border: 1px solid #000000;
- border-color: #0d0d0d #000000 #000000;
- border-radius: 5px;
- color: #000000;
- cursor: pointer;
- outline: none;
- padding: 5px 5px;
-}
-.Select-control:hover {
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
-}
-.is-open > .Select-control {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- background: white;
- border-color: #000000 #000000 #0d0d0d;
-}
-.is-focused > .Select-control {
- border-color: #0000ff #1a1aff #1a1aff;
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px rgba(0, 0, 255, 0.5);
- cursor: text;
-}
-.Select-control:after {
- border-color: #999999 transparent transparent;
- border-style: solid;
- border-width: 5px 5px 0;
- content: " ";
- display: block;
- height: 0;
- margin-top: -3px;
- position: absolute;
- right: 5px;
- top: 50%;
- width: 0;
-}
-.is-open > .Select-control:after {
- border-color: transparent transparent #999999;
- border-width: 0 5px 5px;
-}
-.Select-input {
- cursor: pointer;
- border: 0 none;
- background: none transparent;
- outline: none;
- -webkit-appearance: none;
-}
-.Select-input::-moz-placeholder {
- color: #aaaaaa;
- opacity: 1;
-}
-.Select-input:-ms-input-placeholder {
- color: #aaaaaa;
-}
-.Select-input::-webkit-input-placeholder {
- color: #aaaaaa;
-}
-.is-focused .Select-input {
- cursor: text;
-}
-.Select-clear {
- color: #999999;
- cursor: pointer;
- display: inline-block;
- font-size: 1.1em;
- padding: 5px 5px;
- position: absolute;
- right: 10px;
- top: 0;
-}
-.Select-clear:hover {
- color: #ff0000;
-}
-.Select-menu {
- border-bottom-left-radius: 5px;
- border-bottom-right-radius: 5px;
- background-color: white;
- border: 1px solid #000000;
- border-top-color: #808080;
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
- margin-top: -1px;
- position: absolute;
- top: 100%;
- width: 100%;
- z-index: 10000;
-}
-.Select-option {
- color: #333333;
- cursor: pointer;
- display: block;
- padding: 5px 5px;
-}
-.Select-option:last-child {
- border-bottom-left-radius: 5px;
- border-bottom-right-radius: 5px;
-}
-.Select-option.is-focused {
- background-color: #f2f9fc;
- color: #000000;
-}
-.Select-noresults {
- color: #666666;
- cursor: default;
- display: block;
- padding: 5px 5px;
-}
-.Select-noresults:last-child {
- border-bottom-left-radius: 5px;
- border-bottom-right-radius: 5px;
-}
diff --git a/examples/src/app.js b/examples/src/app.js
deleted file mode 100644
index 53de9799d6..0000000000
--- a/examples/src/app.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/** @jsx React.DOM */
-
-var React = require('react'),
- Select = require('react-select');
-
-var SelectField = React.createClass({
- render: function() {
- var ops = [
- { label: 'Australian Capital Territory', value: 'australian-capital-territory' },
- { label: 'New South Wales', value: 'new-south-wales' },
- { label: 'Victoria', value: 'victoria' },
- { label: 'Queensland', value: 'queensland' },
- { label: 'Western Australia', value: 'western-australia' },
- { label: 'South Australia', value: 'south-australia' },
- { label: 'Tasmania', value: 'tasmania' },
- { label: 'Northern Territory', value: 'northern-territory' }
- ];
- return
- {this.props.label}
-
-
;
- }
-});
-
-React.renderComponent(
- ,
- document.getElementById('example')
-);
diff --git a/examples/src/example.less b/examples/src/example.less
deleted file mode 100644
index 75f77dc635..0000000000
--- a/examples/src/example.less
+++ /dev/null
@@ -1,104 +0,0 @@
-//
-// Common Example Styles
-// ------------------------------
-
-
-
-// Body
-
-body {
- font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
- font-size: 14px;
- color: #333;
- margin: 0;
- padding: 0;
-}
-
-a {
- color: #08c;
- text-decoration: none;
-
- &:hover {
- text-decoration: underline;
- }
-}
-
-.container {
- margin-left: auto;
- margin-right: auto;
- max-width: 600px;
- padding: 1em;
-}
-
-.footer {
- margin-top: 50px;
- border-top: 1px solid #eee;
- padding: 20px 0;
- font-size: 12px;
- color: #999;
-}
-
-
-// Type
-
-h1,h2,h3,h4,h5,h6 {
- color: #222;
- font-weight: 100;
- margin: 0.5em 0;
-}
-
-
-// Forms
-
-label {
- color: #999;
- display: inline-block;
- font-size: 0.85em;
- font-weight: bold;
- margin: 1em 0;
- text-transform: uppercase;
-}
-
-/*
-
-// include these styles to test normal form fields
-
-.form-input {
- margin-bottom: 15px;
-}
-
-.form-input input {
-
- font-size: 14px;
- width: 100%;
- background-color: white;
- border: 1px solid @select-input-border-color;
- border-color: lighten(@select-input-border-color, 5%) @select-input-border-color darken(@select-input-border-color, 10%);
- border-radius: @select-input-border-radius;
- box-sizing: border-box;
- color: @select-text-color;
- outline: none;
- padding: @select-padding-vertical @select-padding-horizontal;
- transition: all 200ms ease;
-
- &:hover {
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
- }
-
- &:focus {
- border-color: @select-input-border-focus lighten(@select-input-border-focus, 5%) lighten(@select-input-border-focus, 5%);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px fade(@select-input-border-focus,50%);
- }
-}
-
-*/
-
-.form-toolbar {
- margin-top: 15px;
-}
-
-
-//
-// Select Control
-// ------------------------------
-@import "../../less/default.less";
diff --git a/gulpfile.js b/gulpfile.js
deleted file mode 100644
index bdd94cf98e..0000000000
--- a/gulpfile.js
+++ /dev/null
@@ -1,111 +0,0 @@
-var del = require('del'),
- gulp = require('gulp'),
- gutil = require('gulp-util'),
- less = require('gulp-less'),
- browserify = require('browserify'),
- watchify = require('watchify'),
- reactify = require('reactify'),
- source = require('vinyl-source-stream'),
- merge = require('merge-stream'),
- chalk = require('chalk');
-
-/**
- * Clean Everything
- */
-
-gulp.task('clean', function(done) {
- del(['./examples/public/build'], done);
-});
-
-/**
- * Build Default theme from LESS
- */
-
-gulp.task('less', function() {
- return gulp.src('less/default.less')
- .pipe(less())
- .pipe(gulp.dest('dist'));
-});
-
-
-/**
- * Build Examples
- */
-
-function doBundle(target, name, dest) {
- return target.bundle()
- .on('error', function(e) {
- gutil.log('Browserify Error', e);
- })
- .pipe(source(name))
- .pipe(gulp.dest(dest));
-}
-
-function watchBundle(target, name, dest) {
- return watchify(target)
- .on('update', function (scriptIds) {
- scriptIds = scriptIds
- .filter(function(i) { return i.substr(0,2) !== './' })
- .map(function(i) { return chalk.blue(i.replace(__dirname, '')) });
- if (scriptIds.length > 1) {
- gutil.log(scriptIds.length + ' Scripts updated:\n* ' + scriptIds.join('\n* ') + '\nrebuilding...');
- } else {
- gutil.log(scriptIds[0] + ' updated, rebuilding...');
- }
- doBundle(target, name, dest);
- })
- .on('time', function (time) {
- gutil.log(chalk.green(name + ' built in ' + (Math.round(time / 10) / 100) + 's'));
- });
-}
-
-function buildExamples(watch) {
-
- var opts = watch ? watchify.args : {};
-
- opts.debug = true;
- opts.hasExports = true;
-
- var dest = './examples/public/build';
-
- var common = browserify(opts)
- .require('react')
- .require('underscore');
-
- var select = browserify(opts)
- .exclude('react')
- .exclude('underscore')
- .require('./lib/select.js', { expose: 'react-select' });
-
- var app = browserify(opts)
- .add('./examples/src/app.js')
- .exclude('react')
- .exclude('react-select')
- .transform(reactify);
-
- var lessToCSS = gulp.src('examples/src/example.less')
- .pipe(less())
- .pipe(gulp.dest(dest));
-
- if (watch) {
- watchBundle(app, 'app-bundle.js', dest);
- watchBundle(select, 'select-bundle.js', dest);
- // TODO: Watch LESS
- }
-
- return merge(
- doBundle(app, 'app-bundle.js', dest),
- doBundle(select, 'select-bundle.js', dest),
- doBundle(common, 'global-bundle.js', dest),
- lessToCSS
- );
-
-}
-
-gulp.task('build-examples', ['clean'], function() {
- return buildExamples();
-});
-
-gulp.task('watch-examples', ['clean'], function() {
- return buildExamples(true);
-});
diff --git a/examples/public/index.html b/index.html
similarity index 100%
rename from examples/public/index.html
rename to index.html
diff --git a/less/default.less b/less/default.less
deleted file mode 100644
index b12d82bbc5..0000000000
--- a/less/default.less
+++ /dev/null
@@ -1,46 +0,0 @@
-/**
- * React Select
- * ============
- * Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
- * https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
- * MIT License: https://github.com/keystonejs/react-select
-*/
-
-//
-// Select Variables
-// ------------------------------
-
-@select-text-color: #333;
-@select-input-border-color: #ccc;
-@select-input-border-radius: 4px;
-@select-input-placeholder: #aaa;
-@select-input-border-focus: #08c; // blue
-
-@select-padding-vertical: 6px;
-@select-padding-horizontal: 10px;
-
-@select-arrow-color: #999;
-
-@select-menu-zindex: 1000;
-
-@select-option-color: lighten(@select-text-color, 20%);
-@select-option-focused-color: @select-text-color;
-@select-option-focused-bg: #f2f9fc; // pale blue
-
-@select-noresults-color: lighten(@select-text-color, 40%);
-
-@select-clear-color: #999;
-@select-clear-hover-color: #c0392b; // red
-
-
-// wrapper
-
-.Select {
- position: relative;
-}
-
-//
-// Imports
-// ------------------------------
-@import "select-control.less";
-@import "select-menu.less";
diff --git a/less/select-control.less b/less/select-control.less
deleted file mode 100644
index c5bbad3740..0000000000
--- a/less/select-control.less
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// Control
-// ------------------------------
-
-
-// base
-
-.Select-control {
- background-color: white;
- border: 1px solid @select-input-border-color;
- border-color: lighten(@select-input-border-color, 5%) @select-input-border-color darken(@select-input-border-color, 10%);
- border-radius: @select-input-border-radius;
- box-sizing: border-box;
- color: @select-text-color;
- cursor: pointer;
- outline: none;
- padding: @select-padding-vertical @select-padding-horizontal;
- transition: all 200ms ease;
-
- &:hover {
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
- }
-}
-
-.is-open > .Select-control {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- background: white;
- border-color: darken(@select-input-border-color, 10%) @select-input-border-color lighten(@select-input-border-color, 5%);
- cursor: text;
-
- // flip the arrow so its pointing up when the menu is open
- > .Select-indicator {
- border-color: transparent transparent @select-arrow-color;
- border-width: 0 5px 5px;
- }
-}
-
-.is-focused:not(.is-open) > .Select-control {
- border-color: @select-input-border-focus lighten(@select-input-border-focus, 5%) lighten(@select-input-border-focus, 5%);
- box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px fade(@select-input-border-focus,50%);
- cursor: text;
-}
-
-
-// indicator arrow
-
-.Select-indicator {
- border-color: @select-arrow-color transparent transparent;
- border-style: solid;
- border-width: 5px 5px 0;
- content: " ";
- display: block;
- height: 0;
- margin-top: -3px;
- position: absolute;
- right: @select-padding-horizontal;
- top: 50%;
- width: 0;
-}
-
-
-// the actual element users type in
-
-.Select-input {
- background: none transparent;
- border: 0 none;
- cursor: pointer;
- font-family: inherit;
- font-size: inherit;
- outline: none;
- width: 100%;
- -webkit-appearance: none;
-
- &::-moz-placeholder { color: @select-input-placeholder;
- opacity: 1; }
- &:-ms-input-placeholder { color: @select-input-placeholder; }
- &::-webkit-input-placeholder { color: @select-input-placeholder; }
-
- .is-focused & {
- cursor: text;
- }
-}
-
-
-// the little cross that clears the field
-
-.Select-clear {
- // todo: animate transition in
- color: @select-clear-color;
- cursor: pointer;
- display: inline-block;
- font-size: 1.1em; // make a bit more visible and fix line-height issue
- padding: @select-padding-vertical @select-padding-horizontal;
- position: absolute;
- right: (@select-padding-horizontal * 2);
- top: 0;
-
- &:hover {
- color: @select-clear-hover-color;
- }
-}
diff --git a/less/select-menu.less b/less/select-menu.less
deleted file mode 100644
index 3013b4b1a3..0000000000
--- a/less/select-menu.less
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Select Menu
-// ------------------------------
-
-
-// wrapper
-
-.Select-menu {
- border-bottom-left-radius: @select-input-border-radius;
- border-bottom-right-radius: @select-input-border-radius;
- background-color: white;
- border: 1px solid @select-input-border-color;
- border-top-color: mix(white, @select-input-border-color, 50%);
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
- box-sizing: border-box;
- margin-top: -1px;
- max-height: 200px;
- overflow-y: auto;
- position: absolute;
- top: 100%;
- width: 100%;
- z-index: @select-menu-zindex;
- -webkit-overflow-scrolling: touch;
-}
-
-
-// options
-
-.Select-option {
- box-sizing: border-box;
- color: @select-option-color;
- cursor: pointer;
- display: block;
- padding: @select-padding-vertical @select-padding-horizontal;
-
- &:last-child {
- border-bottom-left-radius: @select-input-border-radius;
- border-bottom-right-radius: @select-input-border-radius;
- }
-
- &.is-focused {
- background-color: @select-option-focused-bg;
- color: @select-option-focused-color;
- }
-
-}
-
-
-// no results
-
-.Select-noresults {
- box-sizing: border-box;
- color: @select-noresults-color;
- cursor: default;
- display: block;
- padding: @select-padding-vertical @select-padding-horizontal;
-
- &:last-child {
- border-bottom-left-radius: @select-input-border-radius;
- border-bottom-right-radius: @select-input-border-radius;
- }
-}
diff --git a/less/select.less b/less/select.less
deleted file mode 100644
index b01af94492..0000000000
--- a/less/select.less
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * React Select
- * ============
- * Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
- * https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
- * MIT License: https://github.com/keystonejs/react-select
-*/
-
-/*
-
-Variables
----------
-
-Ensure you have the following variables set before importing this file:
-
-@select-text-color
-@select-input-border-color
-@select-input-border-radius
-@select-input-placeholder
-@select-padding-vertical
-@select-padding-horizontal
-@select-arrow-color
-@select-menu-zindex
-@select-option-color
-@select-option-focused-color
-@select-option-focused-bg
-@select-noresults-color
-@select-clear-color
-@select-clear-hover-color
-
-*/
-
-@import "select-control.less";
-@import "select-menu.less";
diff --git a/lib/select.js b/lib/select.js
deleted file mode 100644
index 6664fa1329..0000000000
--- a/lib/select.js
+++ /dev/null
@@ -1,313 +0,0 @@
-/** @jsx React.DOM */
-
-var _ = require('underscore'),
- React = require('react');
-
-var noop = function() {};
-
-var logEvent = function(msg) {
- console.log(msg);
-};
-
-// comment out this line to debug the control state
-logEvent = noop;
-
-var classes = function() {
- var rtn = [];
- for (var i = 0; i < arguments.length; i++) {
- if ('string' === typeof arguments[i]) {
- rtn.push(arguments[i]);
- } else if (_.isObject(arguments[i])) {
- _.each(arguments[i], function(val, key) {
- if (val) {
- rtn.push(key);
- }
- });
- }
- }
- return rtn.join(' ') || undefined;
-}
-
-var Select = React.createClass({
-
- getInitialState: function() {
- return {
- value: this.props.value,
- inputValue: '',
- placeholder: '',
- focusedOption: null,
- isFocused: false,
- isOpen: false
- };
- },
-
- componentWillMount: function() {
- this.setState(this.getStateFromValue(this.state.value));
- },
-
- getStateFromValue: function(value) {
- var selectedOption = ('string' === typeof value) ? _.findWhere(this.props.options, { value: value }) : value;
- return selectedOption ? {
- value: value,
- inputValue: selectedOption.label,
- placeholder: selectedOption.label,
- focusedOption: selectedOption
- } : {
- value: '',
- inputValue: '',
- placeholder: this.props.placeholder || 'Select...',
- focusedOption: null
- };
- },
-
- keyboardActions: {
- 13: 'selectFocusedOption',
- 27: 'closeOnEscape',
- 38: 'focusPreviousOption',
- 40: 'focusNextOption'
- },
-
- handleKeyDown: function(event) {
- logEvent('------');
- logEvent(event);
- var action = this.keyboardActions[event.keyCode];
- if (!action) {
- return;
- }
- event.preventDefault();
- this[action].call(this);
- },
-
- handleMouseDown: function() {
- logEvent('click: control');
- if (this.state.isOpen) {
- this.setState({
- isOpen: false
- });
- this._controlIsFocused = true;
- this.refs.control.getDOMNode().focus();
- clearTimeout(this.blurTimer);
- } else {
- this.setState({
- isOpen: true,
- inputValue: ''
- });
- if (!this._inputIsFocused) {
- this.refs.input.getDOMNode().focus();
- }
- }
- },
-
- handleFocus: function() {
- if (this._controlIsFocused) return;
- logEvent('focus: control');
- this._controlIsFocused = true;
- clearTimeout(this.blurTimer);
- setTimeout(function() {
- if (!this._inputIsFocused) {
- this.refs.input.getDOMNode().focus();
- }
- }.bind(this), 0);
- this.setState({
- isFocused: true
- });
- },
-
- handleBlur: function(event) {
- if (!this._controlIsFocused) return;
- this._controlIsFocused = false;
- clearTimeout(this.blurTimer);
- this.blurTimer = setTimeout(function() {
- logEvent('blur: control');
- var blurState = this.getStateFromValue(this.state.value);
- blurState.isFocused = false;
- blurState.isOpen = false;
- this.setState(blurState);
- }.bind(this), 100);
- },
-
- handleInputMouseDown: function(event) {
- if (this._inputIsFocused) {
- logEvent('click: input');
- event.stopPropagation();
- }
- },
-
- handleInputFocus: function(event) {
- logEvent('focus: input');
- clearTimeout(this.blurTimer);
- this._inputIsFocused = true;
- },
-
- handleInputBlur: function(event) {
- logEvent('blur: input');
- this._inputIsFocused = false;
- },
-
- handleInputChange: function(event) {
- this.setState({
- isOpen: true,
- inputValue: event.target.value
- });
- },
-
- selectOption: function(option) {
- this.setValue(option);
- this.refs.control.getDOMNode().focus();
- },
-
- setValue: function(option) {
- var newState = this.getStateFromValue(option);
- newState.isOpen = false;
- this.setState(newState);
- },
-
- selectFocusedOption: function() {
- return this.setValue(this.state.focusedOption);
- },
-
- clearValue: function(event) {
- logEvent('clear value');
- this.setValue(null);
- },
-
- closeOnEscape: function() {
- this.setValue(this.state.value);
- },
-
- focusOption: function(op) {
- this.setState({
- focusedOption: op
- });
- },
-
- unfocusOption: function(op) {
- if (this.state.focusedOption === op) {
- this.setState({
- focusedOption: null
- });
- }
- },
-
- focusNextOption: function() {
- this.focusAdjacentOption('next');
- },
-
- focusPreviousOption: function() {
- this.focusAdjacentOption('previous');
- },
-
- focusAdjacentOption: function(dir) {
-
- if (!this.state.isOpen) {
- this.setState({
- isOpen: true,
- inputValue: ''
- });
- return;
- }
-
- var ops = this.filterOptions();
-
- if (!ops.length) {
- return;
- }
-
- var focusedIndex = -1;
-
- for (var i = 0; i < ops.length; i++) {
- if (this.state.focusedOption === ops[i]) {
- focusedIndex = i;
- break;
- }
- }
-
- var focusedOption = ops[0];
-
- if (dir === 'next' && focusedIndex > -1 && focusedIndex < ops.length - 1) {
- focusedOption = ops[focusedIndex + 1];
- } else if (dir === 'previous') {
- if (focusedIndex > 0) {
- focusedOption = ops[focusedIndex - 1];
- } else {
- focusedOption = ops[ops.length - 1];
- }
- }
-
- this.setState({
- focusedOption: focusedOption
- });
-
- },
-
- filterOptions: function() {
- return _.filter(this.props.options, this.filterOption, this);
- },
-
- filterOption: function(op) {
- return (
- !this.state.inputValue
- || op.value.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
- || op.label.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
- );
- },
-
- getOptions: function() {
-
- var ops = {};
-
- _.each(this.filterOptions(), function(op) {
-
- var optionClass = classes({
- 'Select-option': true,
- 'is-focused': this.state.focusedOption === op
- });
-
- var mouseEnter = this.focusOption.bind(this, op),
- mouseLeave = this.unfocusOption.bind(this, op),
- mouseDown = this.selectOption.bind(this, op);
-
- ops[op.value] = React.DOM.div({
- className: optionClass,
- onMouseEnter: mouseEnter,
- onMouseLeave: mouseLeave,
- onMouseDown: mouseDown
- }, op.label);
-
- }, this);
-
- if (_.isEmpty(ops)) {
- ops._no_ops = React.DOM.div({className: "Select-noresults"}, "No results found");
- }
-
- return ops;
-
- },
-
- render: function() {
-
- logEvent('render');
- // console.log(this.state);
-
- var menu = this.state.isOpen ? React.DOM.div({ className: "Select-menu" }, this.getOptions()) : null;
- var clear = this.state.value ? React.DOM.span({ className: "Select-clear", onClick: this.clearValue, dangerouslySetInnerHTML: { __html: '×' } }) : null;
-
- var selectClass = classes('Select', {
- 'is-open': this.state.isOpen,
- 'is-focused': this.state.isFocused
- });
-
- return React.DOM.div({ className: selectClass },
- React.DOM.input({ type: "hidden", ref: "value", name: this.props.name, value: this.state.value }),
- React.DOM.div({ className: "Select-control", tabIndex: "-1", ref: "control", onKeyDown: this.handleKeyDown, onMouseDown: this.handleMouseDown, onFocus: this.handleFocus, onBlur: this.handleBlur },
- React.DOM.input({ className: "Select-input", placeholder: this.state.placeholder, ref: "input", onMouseDown: this.handleInputMouseDown, value: this.state.inputValue, onFocus: this.handleInputFocus, onBlur: this.handleInputBlur, onChange: this.handleInputChange }),
- React.DOM.span({ className: "Select-indicator" }),
- clear
- ),
- menu
- );
- }
-
-});
-
-module.exports = Select;
diff --git a/package.json b/package.json
deleted file mode 100644
index 08ab6fba7e..0000000000
--- a/package.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "react-select",
- "version": "0.0.3",
- "description": "A Select control built with and for React",
- "main": "lib/select.js",
- "author": "Jed Watson",
- "license": "MIT",
- "repository": {
- "type": "git",
- "url": "https://github.com/JedWatson/react-select.git"
- },
- "dependencies": {
- "underscore": "~1.7.0",
- "react": "~0.11.1"
- },
- "devDependencies": {
- "browserify": "~5.11.1",
- "chalk": "~0.5.1",
- "del": "~0.1.2",
- "gulp": "~3.8.5",
- "gulp-less": "~1.3.5",
- "gulp-util": "~3.0.0",
- "merge-stream": "~0.1.5",
- "reactify": "~0.14.0",
- "vinyl-source-stream": "~0.1.1",
- "watchify": "~1.0.1"
- },
- "scripts": {
- "test": "echo \"no tests yet\" && exit 0"
- },
- "tags": [
- "react",
- "combobox",
- "select",
- "ui"
- ]
-}
From f5b45a16dc40524ca18e1e4d6393cc5f5495a740 Mon Sep 17 00:00:00 2001
From: Jed Watson
Date: Tue, 9 Sep 2014 15:20:21 +1000
Subject: [PATCH 02/31] Update 2014-09-09T05:20:21.227Z
---
.gitignore | 23 ---------
build/app-bundle.js | 56 ++++++++++++++++++++-
build/example.css | 46 +++++++++++++----
build/select-bundle.js | 109 ++++++++++++++++++++++++++++++++---------
index.html | 4 ++
5 files changed, 181 insertions(+), 57 deletions(-)
delete mode 100644 .gitignore
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 336f730cec..0000000000
--- a/.gitignore
+++ /dev/null
@@ -1,23 +0,0 @@
-# Logs
-logs
-*.log
-
-# Runtime data
-pids
-*.pid
-*.seed
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Compiled binary addons (http://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directory
-node_modules
diff --git a/build/app-bundle.js b/build/app-bundle.js
index 1cb38b7859..f751a898f1 100755
--- a/build/app-bundle.js
+++ b/build/app-bundle.js
@@ -22,11 +22,63 @@ var SelectField = React.createClass({displayName: 'SelectField',
);
}
});
+
+var RemoteSelectField = React.createClass({displayName: 'RemoteSelectField',
+ loadOptions: function(input, callback) {
+
+ var rtn = {
+ options: [
+ { label: 'One', value: 'one' },
+ { label: 'Two', value: 'two' },
+ { label: 'Three', value: 'three' }
+ ],
+ complete: true
+ };
+
+ if (input.slice(0,1) === 'a') {
+ if (input.slice(0,2) === 'ab') {
+ rtn = {
+ options: [
+ { label: 'AB', value: 'ab' },
+ { label: 'ABC', value: 'abc' },
+ { label: 'ABCD', value: 'abcd' }
+ ],
+ complete: true
+ };
+ } else {
+ rtn = {
+ options: [
+ { label: 'A', value: 'a' },
+ { label: 'AA', value: 'aa' },
+ { label: 'AB', value: 'ab' }
+ ],
+ complete: false
+ };
+ }
+ } else if (!input.length) {
+ rtn.complete = false;
+ }
+
+ setTimeout(function() {
+ callback(null, rtn);
+ }, 500);
+
+ },
+ render: function() {
+ return React.DOM.div(null,
+ React.DOM.label(null, this.props.label),
+ Select({asyncOptions: this.loadOptions, value: this.props.value})
+ );
+ }
+});
React.renderComponent(
- SelectField({label: "State:"}),
+ React.DOM.div(null,
+ SelectField({label: "State:"}),
+ RemoteSelectField({label: "Remote:"})
+ ),
document.getElementById('example')
);
},{"react":undefined,"react-select":undefined}]},{},[1])
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9KZWQvRGV2ZWxvcG1lbnQvUGFja2FnZXMvcmVhY3Qtc2VsZWN0L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIuL2V4YW1wbGVzL3NyYy9hcHAuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qKiBAanN4IFJlYWN0LkRPTSAqL1xuXG52YXIgUmVhY3QgPSByZXF1aXJlKCdyZWFjdCcpLFxuXHRTZWxlY3QgPSByZXF1aXJlKCdyZWFjdC1zZWxlY3QnKTtcbiBcbnZhciBTZWxlY3RGaWVsZCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtkaXNwbGF5TmFtZTogJ1NlbGVjdEZpZWxkJyxcblx0cmVuZGVyOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3BzID0gW1xuXHRcdFx0eyBsYWJlbDogJ0F1c3RyYWxpYW4gQ2FwaXRhbCBUZXJyaXRvcnknLCB2YWx1ZTogJ2F1c3RyYWxpYW4tY2FwaXRhbC10ZXJyaXRvcnknIH0sXG5cdFx0XHR7IGxhYmVsOiAnTmV3IFNvdXRoIFdhbGVzJywgdmFsdWU6ICduZXctc291dGgtd2FsZXMnIH0sXG5cdFx0XHR7IGxhYmVsOiAnVmljdG9yaWEnLCB2YWx1ZTogJ3ZpY3RvcmlhJyB9LFxuXHRcdFx0eyBsYWJlbDogJ1F1ZWVuc2xhbmQnLCB2YWx1ZTogJ3F1ZWVuc2xhbmQnIH0sXG5cdFx0XHR7IGxhYmVsOiAnV2VzdGVybiBBdXN0cmFsaWEnLCB2YWx1ZTogJ3dlc3Rlcm4tYXVzdHJhbGlhJyB9LFxuXHRcdFx0eyBsYWJlbDogJ1NvdXRoIEF1c3RyYWxpYScsIHZhbHVlOiAnc291dGgtYXVzdHJhbGlhJyB9LFxuXHRcdFx0eyBsYWJlbDogJ1Rhc21hbmlhJywgdmFsdWU6ICd0YXNtYW5pYScgfSxcblx0XHRcdHsgbGFiZWw6ICdOb3J0aGVybiBUZXJyaXRvcnknLCB2YWx1ZTogJ25vcnRoZXJuLXRlcnJpdG9yeScgfVxuXHRcdF07XG5cdFx0cmV0dXJuIFJlYWN0LkRPTS5kaXYobnVsbCwgXG5cdFx0XHRSZWFjdC5ET00ubGFiZWwobnVsbCwgdGhpcy5wcm9wcy5sYWJlbCksIFxuXHRcdFx0U2VsZWN0KHtvcHRpb25zOiBvcHMsIHZhbHVlOiB0aGlzLnByb3BzLnZhbHVlfSlcblx0XHQpO1xuXHR9XG59KTtcblxuUmVhY3QucmVuZGVyQ29tcG9uZW50KFxuXHRTZWxlY3RGaWVsZCh7bGFiZWw6IFwiU3RhdGU6XCJ9KSxcblx0ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2V4YW1wbGUnKVxuKTtcbiJdfQ==
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9KZWQvRGV2ZWxvcG1lbnQvUGFja2FnZXMvcmVhY3Qtc2VsZWN0L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIuL2V4YW1wbGVzL3NyYy9hcHAuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiLyoqIEBqc3ggUmVhY3QuRE9NICovXG5cbnZhciBSZWFjdCA9IHJlcXVpcmUoJ3JlYWN0JyksXG5cdFNlbGVjdCA9IHJlcXVpcmUoJ3JlYWN0LXNlbGVjdCcpO1xuIFxudmFyIFNlbGVjdEZpZWxkID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiAnU2VsZWN0RmllbGQnLFxuXHRyZW5kZXI6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvcHMgPSBbXG5cdFx0XHR7IGxhYmVsOiAnQXVzdHJhbGlhbiBDYXBpdGFsIFRlcnJpdG9yeScsIHZhbHVlOiAnYXVzdHJhbGlhbi1jYXBpdGFsLXRlcnJpdG9yeScgfSxcblx0XHRcdHsgbGFiZWw6ICdOZXcgU291dGggV2FsZXMnLCB2YWx1ZTogJ25ldy1zb3V0aC13YWxlcycgfSxcblx0XHRcdHsgbGFiZWw6ICdWaWN0b3JpYScsIHZhbHVlOiAndmljdG9yaWEnIH0sXG5cdFx0XHR7IGxhYmVsOiAnUXVlZW5zbGFuZCcsIHZhbHVlOiAncXVlZW5zbGFuZCcgfSxcblx0XHRcdHsgbGFiZWw6ICdXZXN0ZXJuIEF1c3RyYWxpYScsIHZhbHVlOiAnd2VzdGVybi1hdXN0cmFsaWEnIH0sXG5cdFx0XHR7IGxhYmVsOiAnU291dGggQXVzdHJhbGlhJywgdmFsdWU6ICdzb3V0aC1hdXN0cmFsaWEnIH0sXG5cdFx0XHR7IGxhYmVsOiAnVGFzbWFuaWEnLCB2YWx1ZTogJ3Rhc21hbmlhJyB9LFxuXHRcdFx0eyBsYWJlbDogJ05vcnRoZXJuIFRlcnJpdG9yeScsIHZhbHVlOiAnbm9ydGhlcm4tdGVycml0b3J5JyB9XG5cdFx0XTtcblx0XHRyZXR1cm4gUmVhY3QuRE9NLmRpdihudWxsLCBcblx0XHRcdFJlYWN0LkRPTS5sYWJlbChudWxsLCB0aGlzLnByb3BzLmxhYmVsKSwgXG5cdFx0XHRTZWxlY3Qoe29wdGlvbnM6IG9wcywgdmFsdWU6IHRoaXMucHJvcHMudmFsdWV9KVxuXHRcdCk7XG5cdH1cbn0pO1xuIFxudmFyIFJlbW90ZVNlbGVjdEZpZWxkID0gUmVhY3QuY3JlYXRlQ2xhc3Moe2Rpc3BsYXlOYW1lOiAnUmVtb3RlU2VsZWN0RmllbGQnLFxuXHRsb2FkT3B0aW9uczogZnVuY3Rpb24oaW5wdXQsIGNhbGxiYWNrKSB7XG5cdFx0XG5cdFx0dmFyIHJ0biA9IHtcblx0XHRcdG9wdGlvbnM6IFtcblx0XHRcdFx0eyBsYWJlbDogJ09uZScsIHZhbHVlOiAnb25lJyB9LFxuXHRcdFx0XHR7IGxhYmVsOiAnVHdvJywgdmFsdWU6ICd0d28nIH0sXG5cdFx0XHRcdHsgbGFiZWw6ICdUaHJlZScsIHZhbHVlOiAndGhyZWUnIH1cblx0XHRcdF0sXG5cdFx0XHRjb21wbGV0ZTogdHJ1ZVxuXHRcdH07XG5cdFx0XG5cdFx0aWYgKGlucHV0LnNsaWNlKDAsMSkgPT09ICdhJykge1xuXHRcdFx0aWYgKGlucHV0LnNsaWNlKDAsMikgPT09ICdhYicpIHtcblx0XHRcdFx0cnRuID0ge1xuXHRcdFx0XHRcdG9wdGlvbnM6IFtcblx0XHRcdFx0XHRcdHsgbGFiZWw6ICdBQicsIHZhbHVlOiAnYWInIH0sXG5cdFx0XHRcdFx0XHR7IGxhYmVsOiAnQUJDJywgdmFsdWU6ICdhYmMnIH0sXG5cdFx0XHRcdFx0XHR7IGxhYmVsOiAnQUJDRCcsIHZhbHVlOiAnYWJjZCcgfVxuXHRcdFx0XHRcdF0sXG5cdFx0XHRcdFx0Y29tcGxldGU6IHRydWVcblx0XHRcdFx0fTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHJ0biA9IHtcblx0XHRcdFx0XHRvcHRpb25zOiBbXG5cdFx0XHRcdFx0XHR7IGxhYmVsOiAnQScsIHZhbHVlOiAnYScgfSxcblx0XHRcdFx0XHRcdHsgbGFiZWw6ICdBQScsIHZhbHVlOiAnYWEnIH0sXG5cdFx0XHRcdFx0XHR7IGxhYmVsOiAnQUInLCB2YWx1ZTogJ2FiJyB9XG5cdFx0XHRcdFx0XSxcblx0XHRcdFx0XHRjb21wbGV0ZTogZmFsc2Vcblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHR9IGVsc2UgaWYgKCFpbnB1dC5sZW5ndGgpIHtcblx0XHRcdHJ0bi5jb21wbGV0ZSA9IGZhbHNlO1xuXHRcdH1cblx0XHRcblx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuXHRcdFx0Y2FsbGJhY2sobnVsbCwgcnRuKTtcblx0XHR9LCA1MDApO1xuXHRcdFxuXHR9LFxuXHRyZW5kZXI6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBSZWFjdC5ET00uZGl2KG51bGwsIFxuXHRcdFx0UmVhY3QuRE9NLmxhYmVsKG51bGwsIHRoaXMucHJvcHMubGFiZWwpLCBcblx0XHRcdFNlbGVjdCh7YXN5bmNPcHRpb25zOiB0aGlzLmxvYWRPcHRpb25zLCB2YWx1ZTogdGhpcy5wcm9wcy52YWx1ZX0pXG5cdFx0KTtcblx0fVxufSk7XG5cblJlYWN0LnJlbmRlckNvbXBvbmVudChcblx0UmVhY3QuRE9NLmRpdihudWxsLCBcblx0XHRTZWxlY3RGaWVsZCh7bGFiZWw6IFwiU3RhdGU6XCJ9KSwgXG5cdFx0UmVtb3RlU2VsZWN0RmllbGQoe2xhYmVsOiBcIlJlbW90ZTpcIn0pXG5cdCksXG5cdGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdleGFtcGxlJylcbik7XG4iXX0=
diff --git a/build/example.css b/build/example.css
index 51845c6837..7474f83242 100644
--- a/build/example.css
+++ b/build/example.css
@@ -15,7 +15,7 @@ a:hover {
.container {
margin-left: auto;
margin-right: auto;
- max-width: 600px;
+ max-width: 400px;
padding: 1em;
}
.footer {
@@ -43,6 +43,11 @@ label {
margin: 1em 0;
text-transform: uppercase;
}
+.hint {
+ margin: 15px 0;
+ font-style: italic;
+ color: #999;
+}
/*
// include these styles to test normal form fields
@@ -105,13 +110,13 @@ label {
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
}
.is-open > .Select-control {
- border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
background: white;
border-color: #b3b3b3 #cccccc #d9d9d9;
cursor: text;
}
-.is-open > .Select-control > .Select-indicator {
+.is-open > .Select-control > .Select-arrow {
border-color: transparent transparent #999999;
border-width: 0 5px 5px;
}
@@ -120,7 +125,7 @@ label {
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 5px -1px rgba(0, 136, 204, 0.5);
cursor: text;
}
-.Select-indicator {
+.Select-arrow {
border-color: #999999 transparent transparent;
border-style: solid;
border-width: 5px 5px 0;
@@ -133,6 +138,23 @@ label {
top: 50%;
width: 0;
}
+.Select-loading {
+ -webkit-animation: spin 400ms infinite linear;
+ -o-animation: spin 400ms infinite linear;
+ animation: spin 400ms infinite linear;
+ width: 16px;
+ height: 16px;
+ box-sizing: border-box;
+ border-radius: 50%;
+ border: 2px solid #cccccc;
+ border-right-color: #333333;
+ display: inline-block;
+ position: relative;
+ margin-top: -8px;
+ position: absolute;
+ right: 30px;
+ top: 50%;
+}
.Select-input {
background: none transparent;
border: 0 none;
@@ -170,8 +192,8 @@ label {
color: #c0392b;
}
.Select-menu {
- border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
background-color: white;
border: 1px solid #cccccc;
border-top-color: #e6e6e6;
@@ -194,8 +216,8 @@ label {
padding: 6px 10px;
}
.Select-option:last-child {
- border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
}
.Select-option.is-focused {
background-color: #f2f9fc;
@@ -208,7 +230,13 @@ label {
display: block;
padding: 6px 10px;
}
-.Select-noresults:last-child {
- border-bottom-left-radius: 4px;
- border-bottom-right-radius: 4px;
+@keyframes spin {
+ to {
+ transform: rotate(1turn);
+ }
+}
+@-webkit-keyframes spin {
+ to {
+ -webkit-transform: rotate(1turn);
+ }
}
diff --git a/build/select-bundle.js b/build/select-bundle.js
index c343859b30..d8fff65345 100755
--- a/build/select-bundle.js
+++ b/build/select-bundle.js
@@ -29,21 +29,38 @@ var classes = function() {
return rtn.join(' ') || undefined;
}
+var requestId = 0;
+
var Select = React.createClass({
-
+
+ getDefaultProps: function() {
+ return {
+ autoload: true
+ };
+ },
+
getInitialState: function() {
return {
value: this.props.value,
inputValue: '',
placeholder: '',
+ options: this.props.options || [],
focusedOption: null,
isFocused: false,
- isOpen: false
+ isOpen: false,
+ isLoading: false
};
},
componentWillMount: function() {
+
+ this._optionsCache = {};
this.setState(this.getStateFromValue(this.state.value));
+
+ if (this.props.asyncOptions && this.props.autoload) {
+ this.autoloadAsyncOptions();
+ }
+
},
getStateFromValue: function(value) {
@@ -146,10 +163,67 @@ var Select = React.createClass({
},
handleInputChange: function(event) {
- this.setState({
- isOpen: true,
- inputValue: event.target.value
- });
+ if (this.props.asyncOptions) {
+ this.setState({
+ isLoading: true,
+ inputValue: event.target.value
+ });
+ this.loadAsyncOptions(event.target.value, {
+ isLoading: false,
+ isOpen: true
+ });
+ } else {
+ this.setState({
+ isOpen: true,
+ inputValue: event.target.value
+ });
+ }
+ },
+
+ autoloadAsyncOptions: function() {
+ this.loadAsyncOptions('', {}, function() {});
+ },
+
+ loadAsyncOptions: function(input, state) {
+
+ for (var i = 0; i <= input.length; i++) {
+ var cacheKey = input.slice(0, i);
+ if (this._optionsCache[cacheKey] && (input === cacheKey || this._optionsCache[cacheKey].complete)) {
+ this.setState(_.extend({
+ options: this._optionsCache[cacheKey].options
+ }, state));
+ return;
+ }
+ }
+
+ var thisRequestId = this._currentRequestId = requestId++;
+
+ this.props.asyncOptions(input, function(err, data) {
+
+ this._optionsCache[input] = data;
+
+ if (thisRequestId !== this._currentRequestId) {
+ return;
+ }
+
+ this.setState(_.extend({
+ options: data.options
+ }, state));
+
+ }.bind(this));
+
+ },
+
+ filterOptions: function() {
+ return _.filter(this.state.options, this.filterOption, this);
+ },
+
+ filterOption: function(op) {
+ return (
+ !this.state.inputValue
+ || op.value.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
+ || op.label.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
+ );
},
selectOption: function(option) {
@@ -241,19 +315,7 @@ var Select = React.createClass({
},
- filterOptions: function() {
- return _.filter(this.props.options, this.filterOption, this);
- },
-
- filterOption: function(op) {
- return (
- !this.state.inputValue
- || op.value.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
- || op.label.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
- );
- },
-
- getOptions: function() {
+ buildMenu: function() {
var ops = {};
@@ -288,9 +350,9 @@ var Select = React.createClass({
render: function() {
logEvent('render');
- // console.log(this.state);
- var menu = this.state.isOpen ? React.DOM.div({ className: "Select-menu" }, this.getOptions()) : null;
+ var menu = this.state.isOpen ? React.DOM.div({ className: "Select-menu" }, this.buildMenu()) : null;
+ var loading = this.state.isLoading ? React.DOM.span({ className: "Select-loading" }) : null;
var clear = this.state.value ? React.DOM.span({ className: "Select-clear", onClick: this.clearValue, dangerouslySetInnerHTML: { __html: '×' } }) : null;
var selectClass = classes('Select', {
@@ -302,7 +364,8 @@ var Select = React.createClass({
React.DOM.input({ type: "hidden", ref: "value", name: this.props.name, value: this.state.value }),
React.DOM.div({ className: "Select-control", tabIndex: "-1", ref: "control", onKeyDown: this.handleKeyDown, onMouseDown: this.handleMouseDown, onFocus: this.handleFocus, onBlur: this.handleBlur },
React.DOM.input({ className: "Select-input", placeholder: this.state.placeholder, ref: "input", onMouseDown: this.handleInputMouseDown, value: this.state.inputValue, onFocus: this.handleInputFocus, onBlur: this.handleInputBlur, onChange: this.handleInputChange }),
- React.DOM.span({ className: "Select-indicator" }),
+ React.DOM.span({ className: "Select-arrow" }),
+ loading,
clear
),
menu
@@ -314,4 +377,4 @@ var Select = React.createClass({
module.exports = Select;
},{"react":undefined,"underscore":undefined}]},{},[])
-//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9KZWQvRGV2ZWxvcG1lbnQvUGFja2FnZXMvcmVhY3Qtc2VsZWN0L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIuL2xpYi9zZWxlY3QuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qKiBAanN4IFJlYWN0LkRPTSAqL1xuXG52YXIgXyA9IHJlcXVpcmUoJ3VuZGVyc2NvcmUnKSxcblx0UmVhY3QgPSByZXF1aXJlKCdyZWFjdCcpO1xuXG52YXIgbm9vcCA9IGZ1bmN0aW9uKCkge307XG5cbnZhciBsb2dFdmVudCA9IGZ1bmN0aW9uKG1zZykge1xuXHRjb25zb2xlLmxvZyhtc2cpO1xufTtcblxuLy8gY29tbWVudCBvdXQgdGhpcyBsaW5lIHRvIGRlYnVnIHRoZSBjb250cm9sIHN0YXRlXG5sb2dFdmVudCA9IG5vb3A7XG5cbnZhciBjbGFzc2VzID0gZnVuY3Rpb24oKSB7XG5cdHZhciBydG4gPSBbXTtcblx0Zm9yICh2YXIgaSA9IDA7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcblx0XHRpZiAoJ3N0cmluZycgPT09IHR5cGVvZiBhcmd1bWVudHNbaV0pIHtcblx0XHRcdHJ0bi5wdXNoKGFyZ3VtZW50c1tpXSk7XG5cdFx0fSBlbHNlIGlmIChfLmlzT2JqZWN0KGFyZ3VtZW50c1tpXSkpIHtcblx0XHRcdF8uZWFjaChhcmd1bWVudHNbaV0sIGZ1bmN0aW9uKHZhbCwga2V5KSB7XG5cdFx0XHRcdGlmICh2YWwpIHtcblx0XHRcdFx0XHRydG4ucHVzaChrZXkpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIHJ0bi5qb2luKCcgJykgfHwgdW5kZWZpbmVkO1xufVxuXG52YXIgU2VsZWN0ID0gUmVhY3QuY3JlYXRlQ2xhc3Moe1xuXHRcdFxuXHRnZXRJbml0aWFsU3RhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB7XG5cdFx0XHR2YWx1ZTogdGhpcy5wcm9wcy52YWx1ZSxcblx0XHRcdGlucHV0VmFsdWU6ICcnLFxuXHRcdFx0cGxhY2Vob2xkZXI6ICcnLFxuXHRcdFx0Zm9jdXNlZE9wdGlvbjogbnVsbCxcblx0XHRcdGlzRm9jdXNlZDogZmFsc2UsXG5cdFx0XHRpc09wZW46IGZhbHNlXG5cdFx0fTtcblx0fSxcblx0XG5cdGNvbXBvbmVudFdpbGxNb3VudDogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5zZXRTdGF0ZSh0aGlzLmdldFN0YXRlRnJvbVZhbHVlKHRoaXMuc3RhdGUudmFsdWUpKTtcblx0fSxcblx0XG5cdGdldFN0YXRlRnJvbVZhbHVlOiBmdW5jdGlvbih2YWx1ZSkge1xuXHRcdHZhciBzZWxlY3RlZE9wdGlvbiA9ICgnc3RyaW5nJyA9PT0gdHlwZW9mIHZhbHVlKSA/IF8uZmluZFdoZXJlKHRoaXMucHJvcHMub3B0aW9ucywgeyB2YWx1ZTogdmFsdWUgfSkgOiB2YWx1ZTtcblx0XHRyZXR1cm4gc2VsZWN0ZWRPcHRpb24gPyB7XG5cdFx0XHR2YWx1ZTogdmFsdWUsXG5cdFx0XHRpbnB1dFZhbHVlOiBzZWxlY3RlZE9wdGlvbi5sYWJlbCxcblx0XHRcdHBsYWNlaG9sZGVyOiBzZWxlY3RlZE9wdGlvbi5sYWJlbCxcblx0XHRcdGZvY3VzZWRPcHRpb246IHNlbGVjdGVkT3B0aW9uXG5cdFx0fSA6IHtcblx0XHRcdHZhbHVlOiAnJyxcblx0XHRcdGlucHV0VmFsdWU6ICcnLFxuXHRcdFx0cGxhY2Vob2xkZXI6IHRoaXMucHJvcHMucGxhY2Vob2xkZXIgfHwgJ1NlbGVjdC4uLicsXG5cdFx0XHRmb2N1c2VkT3B0aW9uOiBudWxsXG5cdFx0fTtcblx0fSxcblx0XG5cdGtleWJvYXJkQWN0aW9uczoge1xuXHRcdDEzOiAnc2VsZWN0Rm9jdXNlZE9wdGlvbicsXG5cdFx0Mjc6ICdjbG9zZU9uRXNjYXBlJyxcblx0XHQzODogJ2ZvY3VzUHJldmlvdXNPcHRpb24nLFxuXHRcdDQwOiAnZm9jdXNOZXh0T3B0aW9uJ1xuXHR9LFxuXHRcblx0aGFuZGxlS2V5RG93bjogZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRsb2dFdmVudCgnLS0tLS0tJyk7XG5cdFx0bG9nRXZlbnQoZXZlbnQpO1xuXHRcdHZhciBhY3Rpb24gPSB0aGlzLmtleWJvYXJkQWN0aW9uc1tldmVudC5rZXlDb2RlXTtcblx0XHRpZiAoIWFjdGlvbikge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdHRoaXNbYWN0aW9uXS5jYWxsKHRoaXMpO1xuXHR9LFxuXHRcblx0aGFuZGxlTW91c2VEb3duOiBmdW5jdGlvbigpIHtcblx0XHRsb2dFdmVudCgnY2xpY2s6IGNvbnRyb2wnKTtcblx0XHRpZiAodGhpcy5zdGF0ZS5pc09wZW4pIHtcblx0XHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0XHRpc09wZW46IGZhbHNlXG5cdFx0XHR9KTtcblx0XHRcdHRoaXMuX2NvbnRyb2xJc0ZvY3VzZWQgPSB0cnVlO1xuXHRcdFx0dGhpcy5yZWZzLmNvbnRyb2wuZ2V0RE9NTm9kZSgpLmZvY3VzKCk7XG5cdFx0XHRjbGVhclRpbWVvdXQodGhpcy5ibHVyVGltZXIpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLnNldFN0YXRlKHtcblx0XHRcdFx0aXNPcGVuOiB0cnVlLFxuXHRcdFx0XHRpbnB1dFZhbHVlOiAnJ1xuXHRcdFx0fSk7XG5cdFx0XHRpZiAoIXRoaXMuX2lucHV0SXNGb2N1c2VkKSB7XG5cdFx0XHRcdHRoaXMucmVmcy5pbnB1dC5nZXRET01Ob2RlKCkuZm9jdXMoKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cdFxuXHRoYW5kbGVGb2N1czogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKHRoaXMuX2NvbnRyb2xJc0ZvY3VzZWQpIHJldHVybjtcblx0XHRsb2dFdmVudCgnZm9jdXM6IGNvbnRyb2wnKTtcblx0XHR0aGlzLl9jb250cm9sSXNGb2N1c2VkID0gdHJ1ZTtcblx0XHRjbGVhclRpbWVvdXQodGhpcy5ibHVyVGltZXIpO1xuXHRcdHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoIXRoaXMuX2lucHV0SXNGb2N1c2VkKSB7XG5cdFx0XHRcdHRoaXMucmVmcy5pbnB1dC5nZXRET01Ob2RlKCkuZm9jdXMoKTtcblx0XHRcdH1cblx0XHR9LmJpbmQodGhpcyksIDApO1xuXHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0aXNGb2N1c2VkOiB0cnVlXG5cdFx0fSk7XG5cdH0sXG5cdFxuXHRoYW5kbGVCbHVyOiBmdW5jdGlvbihldmVudCkge1xuXHRcdGlmICghdGhpcy5fY29udHJvbElzRm9jdXNlZCkgcmV0dXJuO1xuXHRcdHRoaXMuX2NvbnRyb2xJc0ZvY3VzZWQgPSBmYWxzZTtcblx0XHRjbGVhclRpbWVvdXQodGhpcy5ibHVyVGltZXIpO1xuXHRcdHRoaXMuYmx1clRpbWVyID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcblx0XHRcdGxvZ0V2ZW50KCdibHVyOiBjb250cm9sJyk7XG5cdFx0XHR2YXIgYmx1clN0YXRlID0gdGhpcy5nZXRTdGF0ZUZyb21WYWx1ZSh0aGlzLnN0YXRlLnZhbHVlKTtcblx0XHRcdGJsdXJTdGF0ZS5pc0ZvY3VzZWQgPSBmYWxzZTtcblx0XHRcdGJsdXJTdGF0ZS5pc09wZW4gPSBmYWxzZTtcblx0XHRcdHRoaXMuc2V0U3RhdGUoYmx1clN0YXRlKTtcblx0XHR9LmJpbmQodGhpcyksIDEwMCk7XG5cdH0sXG5cdFxuXHRoYW5kbGVJbnB1dE1vdXNlRG93bjogZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRpZiAodGhpcy5faW5wdXRJc0ZvY3VzZWQpIHtcblx0XHRcdGxvZ0V2ZW50KCdjbGljazogaW5wdXQnKTtcblx0XHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdH1cblx0fSxcblx0XG5cdGhhbmRsZUlucHV0Rm9jdXM6IGZ1bmN0aW9uKGV2ZW50KSB7XG5cdFx0bG9nRXZlbnQoJ2ZvY3VzOiBpbnB1dCcpO1xuXHRcdGNsZWFyVGltZW91dCh0aGlzLmJsdXJUaW1lcik7XG5cdFx0dGhpcy5faW5wdXRJc0ZvY3VzZWQgPSB0cnVlO1xuXHR9LFxuXHRcblx0aGFuZGxlSW5wdXRCbHVyOiBmdW5jdGlvbihldmVudCkge1xuXHRcdGxvZ0V2ZW50KCdibHVyOiBpbnB1dCcpO1xuXHRcdHRoaXMuX2lucHV0SXNGb2N1c2VkID0gZmFsc2U7XG5cdH0sXG5cdFxuXHRoYW5kbGVJbnB1dENoYW5nZTogZnVuY3Rpb24oZXZlbnQpIHtcblx0XHR0aGlzLnNldFN0YXRlKHtcblx0XHRcdGlzT3BlbjogdHJ1ZSxcblx0XHRcdGlucHV0VmFsdWU6IGV2ZW50LnRhcmdldC52YWx1ZVxuXHRcdH0pO1xuXHR9LFxuXHRcblx0c2VsZWN0T3B0aW9uOiBmdW5jdGlvbihvcHRpb24pIHtcblx0XHR0aGlzLnNldFZhbHVlKG9wdGlvbik7XG5cdFx0dGhpcy5yZWZzLmNvbnRyb2wuZ2V0RE9NTm9kZSgpLmZvY3VzKCk7XG5cdH0sXG5cdFxuXHRzZXRWYWx1ZTogZnVuY3Rpb24ob3B0aW9uKSB7XG5cdFx0dmFyIG5ld1N0YXRlID0gdGhpcy5nZXRTdGF0ZUZyb21WYWx1ZShvcHRpb24pO1xuXHRcdG5ld1N0YXRlLmlzT3BlbiA9IGZhbHNlO1xuXHRcdHRoaXMuc2V0U3RhdGUobmV3U3RhdGUpO1xuXHR9LFxuXHRcblx0c2VsZWN0Rm9jdXNlZE9wdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuc2V0VmFsdWUodGhpcy5zdGF0ZS5mb2N1c2VkT3B0aW9uKTtcblx0fSxcblx0XG5cdGNsZWFyVmFsdWU6IGZ1bmN0aW9uKGV2ZW50KSB7XG5cdFx0bG9nRXZlbnQoJ2NsZWFyIHZhbHVlJyk7XG5cdFx0dGhpcy5zZXRWYWx1ZShudWxsKTtcblx0fSxcblx0XG5cdGNsb3NlT25Fc2NhcGU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuc2V0VmFsdWUodGhpcy5zdGF0ZS52YWx1ZSk7XG5cdH0sXG5cdFxuXHRmb2N1c09wdGlvbjogZnVuY3Rpb24ob3ApIHtcblx0XHR0aGlzLnNldFN0YXRlKHtcblx0XHRcdGZvY3VzZWRPcHRpb246IG9wXG5cdFx0fSk7XG5cdH0sXG5cdFxuXHR1bmZvY3VzT3B0aW9uOiBmdW5jdGlvbihvcCkge1xuXHRcdGlmICh0aGlzLnN0YXRlLmZvY3VzZWRPcHRpb24gPT09IG9wKSB7XG5cdFx0XHR0aGlzLnNldFN0YXRlKHtcblx0XHRcdFx0Zm9jdXNlZE9wdGlvbjogbnVsbFxuXHRcdFx0fSk7XG5cdFx0fVxuXHR9LFxuXHRcblx0Zm9jdXNOZXh0T3B0aW9uOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmZvY3VzQWRqYWNlbnRPcHRpb24oJ25leHQnKTtcblx0fSxcblx0XG5cdGZvY3VzUHJldmlvdXNPcHRpb246IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuZm9jdXNBZGphY2VudE9wdGlvbigncHJldmlvdXMnKTtcblx0fSxcblx0XG5cdGZvY3VzQWRqYWNlbnRPcHRpb246IGZ1bmN0aW9uKGRpcikge1xuXHRcdFxuXHRcdGlmICghdGhpcy5zdGF0ZS5pc09wZW4pIHtcblx0XHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0XHRpc09wZW46IHRydWUsXG5cdFx0XHRcdGlucHV0VmFsdWU6ICcnXG5cdFx0XHR9KTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0XG5cdFx0dmFyIG9wcyA9IHRoaXMuZmlsdGVyT3B0aW9ucygpO1xuXHRcdFxuXHRcdGlmICghb3BzLmxlbmd0aCkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRcblx0XHR2YXIgZm9jdXNlZEluZGV4ID0gLTE7XG5cdFx0XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCBvcHMubGVuZ3RoOyBpKyspIHtcblx0XHRcdGlmICh0aGlzLnN0YXRlLmZvY3VzZWRPcHRpb24gPT09IG9wc1tpXSkge1xuXHRcdFx0XHRmb2N1c2VkSW5kZXggPSBpO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHR9XG5cdFx0XG5cdFx0dmFyIGZvY3VzZWRPcHRpb24gPSBvcHNbMF07XG5cdFx0XG5cdFx0aWYgKGRpciA9PT0gJ25leHQnICYmIGZvY3VzZWRJbmRleCA+IC0xICYmIGZvY3VzZWRJbmRleCA8IG9wcy5sZW5ndGggLSAxKSB7XG5cdFx0XHRmb2N1c2VkT3B0aW9uID0gb3BzW2ZvY3VzZWRJbmRleCArIDFdO1xuXHRcdH0gZWxzZSBpZiAoZGlyID09PSAncHJldmlvdXMnKSB7XG5cdFx0XHRpZiAoZm9jdXNlZEluZGV4ID4gMCkge1xuXHRcdFx0XHRmb2N1c2VkT3B0aW9uID0gb3BzW2ZvY3VzZWRJbmRleCAtIDFdO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Zm9jdXNlZE9wdGlvbiA9IG9wc1tvcHMubGVuZ3RoIC0gMV07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdFxuXHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0Zm9jdXNlZE9wdGlvbjogZm9jdXNlZE9wdGlvblxuXHRcdH0pO1xuXHRcdFxuXHR9LFxuXHRcblx0ZmlsdGVyT3B0aW9uczogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIF8uZmlsdGVyKHRoaXMucHJvcHMub3B0aW9ucywgdGhpcy5maWx0ZXJPcHRpb24sIHRoaXMpO1xuXHR9LFxuXHRcblx0ZmlsdGVyT3B0aW9uOiBmdW5jdGlvbihvcCkge1xuXHRcdHJldHVybiAoXG5cdFx0XHQhdGhpcy5zdGF0ZS5pbnB1dFZhbHVlXG5cdFx0XHR8fCBvcC52YWx1ZS50b0xvd2VyQ2FzZSgpLmluZGV4T2YodGhpcy5zdGF0ZS5pbnB1dFZhbHVlLnRvTG93ZXJDYXNlKCkpID49IDBcblx0XHRcdHx8IG9wLmxhYmVsLnRvTG93ZXJDYXNlKCkuaW5kZXhPZih0aGlzLnN0YXRlLmlucHV0VmFsdWUudG9Mb3dlckNhc2UoKSkgPj0gMFxuXHRcdCk7XG5cdH0sXG5cdFxuXHRnZXRPcHRpb25zOiBmdW5jdGlvbigpIHtcblx0XHRcblx0XHR2YXIgb3BzID0ge307XG5cdFx0XG5cdFx0Xy5lYWNoKHRoaXMuZmlsdGVyT3B0aW9ucygpLCBmdW5jdGlvbihvcCkge1xuXHRcdFx0XG5cdFx0XHR2YXIgb3B0aW9uQ2xhc3MgPSBjbGFzc2VzKHtcblx0XHRcdFx0J1NlbGVjdC1vcHRpb24nOiB0cnVlLFxuXHRcdFx0XHQnaXMtZm9jdXNlZCc6IHRoaXMuc3RhdGUuZm9jdXNlZE9wdGlvbiA9PT0gb3Bcblx0XHRcdH0pO1xuXHRcdFx0XG5cdFx0XHR2YXIgbW91c2VFbnRlciA9IHRoaXMuZm9jdXNPcHRpb24uYmluZCh0aGlzLCBvcCksXG5cdFx0XHRcdG1vdXNlTGVhdmUgPSB0aGlzLnVuZm9jdXNPcHRpb24uYmluZCh0aGlzLCBvcCksXG5cdFx0XHRcdG1vdXNlRG93biA9IHRoaXMuc2VsZWN0T3B0aW9uLmJpbmQodGhpcywgb3ApO1xuXHRcdFx0XG5cdFx0XHRvcHNbb3AudmFsdWVdID0gUmVhY3QuRE9NLmRpdih7XG5cdFx0XHRcdGNsYXNzTmFtZTogb3B0aW9uQ2xhc3MsXG5cdFx0XHRcdG9uTW91c2VFbnRlcjogbW91c2VFbnRlcixcblx0XHRcdFx0b25Nb3VzZUxlYXZlOiBtb3VzZUxlYXZlLFxuXHRcdFx0XHRvbk1vdXNlRG93bjogbW91c2VEb3duXG5cdFx0XHR9LCBvcC5sYWJlbCk7XG5cdFx0XHRcblx0XHR9LCB0aGlzKTtcblx0XHRcblx0XHRpZiAoXy5pc0VtcHR5KG9wcykpIHtcblx0XHRcdG9wcy5fbm9fb3BzID0gUmVhY3QuRE9NLmRpdih7Y2xhc3NOYW1lOiBcIlNlbGVjdC1ub3Jlc3VsdHNcIn0sIFwiTm8gcmVzdWx0cyBmb3VuZFwiKTtcblx0XHR9XG5cdFx0XG5cdFx0cmV0dXJuIG9wcztcblx0XHRcblx0fSxcblx0XG5cdHJlbmRlcjogZnVuY3Rpb24oKSB7XG5cdFx0XG5cdFx0bG9nRXZlbnQoJ3JlbmRlcicpO1xuXHRcdC8vIGNvbnNvbGUubG9nKHRoaXMuc3RhdGUpO1xuXHRcdFxuXHRcdHZhciBtZW51ID0gdGhpcy5zdGF0ZS5pc09wZW4gPyBSZWFjdC5ET00uZGl2KHsgY2xhc3NOYW1lOiBcIlNlbGVjdC1tZW51XCIgfSwgdGhpcy5nZXRPcHRpb25zKCkpIDogbnVsbDtcblx0XHR2YXIgY2xlYXIgPSB0aGlzLnN0YXRlLnZhbHVlID8gUmVhY3QuRE9NLnNwYW4oeyBjbGFzc05hbWU6IFwiU2VsZWN0LWNsZWFyXCIsIG9uQ2xpY2s6IHRoaXMuY2xlYXJWYWx1ZSwgZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUw6IHsgX19odG1sOiAnJnRpbWVzOycgfSB9KSA6IG51bGw7XG5cdFx0XG5cdFx0dmFyIHNlbGVjdENsYXNzID0gY2xhc3NlcygnU2VsZWN0Jywge1xuXHRcdFx0J2lzLW9wZW4nOiB0aGlzLnN0YXRlLmlzT3Blbixcblx0XHRcdCdpcy1mb2N1c2VkJzogdGhpcy5zdGF0ZS5pc0ZvY3VzZWRcblx0XHR9KTtcblx0XHRcblx0XHRyZXR1cm4gUmVhY3QuRE9NLmRpdih7IGNsYXNzTmFtZTogc2VsZWN0Q2xhc3MgfSwgXG5cdFx0XHRSZWFjdC5ET00uaW5wdXQoeyB0eXBlOiBcImhpZGRlblwiLCByZWY6IFwidmFsdWVcIiwgbmFtZTogdGhpcy5wcm9wcy5uYW1lLCB2YWx1ZTogdGhpcy5zdGF0ZS52YWx1ZSB9KSwgXG5cdFx0XHRSZWFjdC5ET00uZGl2KHsgY2xhc3NOYW1lOiBcIlNlbGVjdC1jb250cm9sXCIsIHRhYkluZGV4OiBcIi0xXCIsIHJlZjogXCJjb250cm9sXCIsIG9uS2V5RG93bjogdGhpcy5oYW5kbGVLZXlEb3duLCBvbk1vdXNlRG93bjogdGhpcy5oYW5kbGVNb3VzZURvd24sIG9uRm9jdXM6IHRoaXMuaGFuZGxlRm9jdXMsIG9uQmx1cjogdGhpcy5oYW5kbGVCbHVyIH0sIFxuXHRcdFx0XHRSZWFjdC5ET00uaW5wdXQoeyBjbGFzc05hbWU6IFwiU2VsZWN0LWlucHV0XCIsIHBsYWNlaG9sZGVyOiB0aGlzLnN0YXRlLnBsYWNlaG9sZGVyLCByZWY6IFwiaW5wdXRcIiwgb25Nb3VzZURvd246IHRoaXMuaGFuZGxlSW5wdXRNb3VzZURvd24sIHZhbHVlOiB0aGlzLnN0YXRlLmlucHV0VmFsdWUsIG9uRm9jdXM6IHRoaXMuaGFuZGxlSW5wdXRGb2N1cywgb25CbHVyOiB0aGlzLmhhbmRsZUlucHV0Qmx1ciwgb25DaGFuZ2U6IHRoaXMuaGFuZGxlSW5wdXRDaGFuZ2UgfSksIFxuXHRcdFx0XHRSZWFjdC5ET00uc3Bhbih7IGNsYXNzTmFtZTogXCJTZWxlY3QtaW5kaWNhdG9yXCIgfSksXG5cdFx0XHRcdGNsZWFyXG5cdFx0XHQpLCBcblx0XHRcdG1lbnVcblx0XHQpO1xuXHR9XG5cdFxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gU2VsZWN0O1xuIl19
+//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi9Vc2Vycy9KZWQvRGV2ZWxvcG1lbnQvUGFja2FnZXMvcmVhY3Qtc2VsZWN0L25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCIuL2xpYi9zZWxlY3QuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qKiBAanN4IFJlYWN0LkRPTSAqL1xuXG52YXIgXyA9IHJlcXVpcmUoJ3VuZGVyc2NvcmUnKSxcblx0UmVhY3QgPSByZXF1aXJlKCdyZWFjdCcpO1xuXG52YXIgbm9vcCA9IGZ1bmN0aW9uKCkge307XG5cbnZhciBsb2dFdmVudCA9IGZ1bmN0aW9uKG1zZykge1xuXHRjb25zb2xlLmxvZyhtc2cpO1xufTtcblxuLy8gY29tbWVudCBvdXQgdGhpcyBsaW5lIHRvIGRlYnVnIHRoZSBjb250cm9sIHN0YXRlXG5sb2dFdmVudCA9IG5vb3A7XG5cbnZhciBjbGFzc2VzID0gZnVuY3Rpb24oKSB7XG5cdHZhciBydG4gPSBbXTtcblx0Zm9yICh2YXIgaSA9IDA7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcblx0XHRpZiAoJ3N0cmluZycgPT09IHR5cGVvZiBhcmd1bWVudHNbaV0pIHtcblx0XHRcdHJ0bi5wdXNoKGFyZ3VtZW50c1tpXSk7XG5cdFx0fSBlbHNlIGlmIChfLmlzT2JqZWN0KGFyZ3VtZW50c1tpXSkpIHtcblx0XHRcdF8uZWFjaChhcmd1bWVudHNbaV0sIGZ1bmN0aW9uKHZhbCwga2V5KSB7XG5cdFx0XHRcdGlmICh2YWwpIHtcblx0XHRcdFx0XHRydG4ucHVzaChrZXkpO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIHJ0bi5qb2luKCcgJykgfHwgdW5kZWZpbmVkO1xufVxuXG52YXIgcmVxdWVzdElkID0gMDtcblxudmFyIFNlbGVjdCA9IFJlYWN0LmNyZWF0ZUNsYXNzKHtcblx0XG5cdGdldERlZmF1bHRQcm9wczogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdGF1dG9sb2FkOiB0cnVlXG5cdFx0fTtcblx0fSxcblx0XG5cdGdldEluaXRpYWxTdGF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHZhbHVlOiB0aGlzLnByb3BzLnZhbHVlLFxuXHRcdFx0aW5wdXRWYWx1ZTogJycsXG5cdFx0XHRwbGFjZWhvbGRlcjogJycsXG5cdFx0XHRvcHRpb25zOiB0aGlzLnByb3BzLm9wdGlvbnMgfHwgW10sXG5cdFx0XHRmb2N1c2VkT3B0aW9uOiBudWxsLFxuXHRcdFx0aXNGb2N1c2VkOiBmYWxzZSxcblx0XHRcdGlzT3BlbjogZmFsc2UsXG5cdFx0XHRpc0xvYWRpbmc6IGZhbHNlXG5cdFx0fTtcblx0fSxcblx0XG5cdGNvbXBvbmVudFdpbGxNb3VudDogZnVuY3Rpb24oKSB7XG5cdFx0XG5cdFx0dGhpcy5fb3B0aW9uc0NhY2hlID0ge307XG5cdFx0dGhpcy5zZXRTdGF0ZSh0aGlzLmdldFN0YXRlRnJvbVZhbHVlKHRoaXMuc3RhdGUudmFsdWUpKTtcblx0XHRcblx0XHRpZiAodGhpcy5wcm9wcy5hc3luY09wdGlvbnMgJiYgdGhpcy5wcm9wcy5hdXRvbG9hZCkge1xuXHRcdFx0dGhpcy5hdXRvbG9hZEFzeW5jT3B0aW9ucygpO1xuXHRcdH1cblx0XHRcblx0fSxcblx0XG5cdGdldFN0YXRlRnJvbVZhbHVlOiBmdW5jdGlvbih2YWx1ZSkge1xuXHRcdHZhciBzZWxlY3RlZE9wdGlvbiA9ICgnc3RyaW5nJyA9PT0gdHlwZW9mIHZhbHVlKSA/IF8uZmluZFdoZXJlKHRoaXMucHJvcHMub3B0aW9ucywgeyB2YWx1ZTogdmFsdWUgfSkgOiB2YWx1ZTtcblx0XHRyZXR1cm4gc2VsZWN0ZWRPcHRpb24gPyB7XG5cdFx0XHR2YWx1ZTogdmFsdWUsXG5cdFx0XHRpbnB1dFZhbHVlOiBzZWxlY3RlZE9wdGlvbi5sYWJlbCxcblx0XHRcdHBsYWNlaG9sZGVyOiBzZWxlY3RlZE9wdGlvbi5sYWJlbCxcblx0XHRcdGZvY3VzZWRPcHRpb246IHNlbGVjdGVkT3B0aW9uXG5cdFx0fSA6IHtcblx0XHRcdHZhbHVlOiAnJyxcblx0XHRcdGlucHV0VmFsdWU6ICcnLFxuXHRcdFx0cGxhY2Vob2xkZXI6IHRoaXMucHJvcHMucGxhY2Vob2xkZXIgfHwgJ1NlbGVjdC4uLicsXG5cdFx0XHRmb2N1c2VkT3B0aW9uOiBudWxsXG5cdFx0fTtcblx0fSxcblx0XG5cdGtleWJvYXJkQWN0aW9uczoge1xuXHRcdDEzOiAnc2VsZWN0Rm9jdXNlZE9wdGlvbicsXG5cdFx0Mjc6ICdjbG9zZU9uRXNjYXBlJyxcblx0XHQzODogJ2ZvY3VzUHJldmlvdXNPcHRpb24nLFxuXHRcdDQwOiAnZm9jdXNOZXh0T3B0aW9uJ1xuXHR9LFxuXHRcblx0aGFuZGxlS2V5RG93bjogZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRsb2dFdmVudCgnLS0tLS0tJyk7XG5cdFx0bG9nRXZlbnQoZXZlbnQpO1xuXHRcdHZhciBhY3Rpb24gPSB0aGlzLmtleWJvYXJkQWN0aW9uc1tldmVudC5rZXlDb2RlXTtcblx0XHRpZiAoIWFjdGlvbikge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdHRoaXNbYWN0aW9uXS5jYWxsKHRoaXMpO1xuXHR9LFxuXHRcblx0aGFuZGxlTW91c2VEb3duOiBmdW5jdGlvbigpIHtcblx0XHRsb2dFdmVudCgnY2xpY2s6IGNvbnRyb2wnKTtcblx0XHRpZiAodGhpcy5zdGF0ZS5pc09wZW4pIHtcblx0XHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0XHRpc09wZW46IGZhbHNlXG5cdFx0XHR9KTtcblx0XHRcdHRoaXMuX2NvbnRyb2xJc0ZvY3VzZWQgPSB0cnVlO1xuXHRcdFx0dGhpcy5yZWZzLmNvbnRyb2wuZ2V0RE9NTm9kZSgpLmZvY3VzKCk7XG5cdFx0XHRjbGVhclRpbWVvdXQodGhpcy5ibHVyVGltZXIpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLnNldFN0YXRlKHtcblx0XHRcdFx0aXNPcGVuOiB0cnVlLFxuXHRcdFx0XHRpbnB1dFZhbHVlOiAnJ1xuXHRcdFx0fSk7XG5cdFx0XHRpZiAoIXRoaXMuX2lucHV0SXNGb2N1c2VkKSB7XG5cdFx0XHRcdHRoaXMucmVmcy5pbnB1dC5nZXRET01Ob2RlKCkuZm9jdXMoKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cdFxuXHRoYW5kbGVGb2N1czogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKHRoaXMuX2NvbnRyb2xJc0ZvY3VzZWQpIHJldHVybjtcblx0XHRsb2dFdmVudCgnZm9jdXM6IGNvbnRyb2wnKTtcblx0XHR0aGlzLl9jb250cm9sSXNGb2N1c2VkID0gdHJ1ZTtcblx0XHRjbGVhclRpbWVvdXQodGhpcy5ibHVyVGltZXIpO1xuXHRcdHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoIXRoaXMuX2lucHV0SXNGb2N1c2VkKSB7XG5cdFx0XHRcdHRoaXMucmVmcy5pbnB1dC5nZXRET01Ob2RlKCkuZm9jdXMoKTtcblx0XHRcdH1cblx0XHR9LmJpbmQodGhpcyksIDApO1xuXHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0aXNGb2N1c2VkOiB0cnVlXG5cdFx0fSk7XG5cdH0sXG5cdFxuXHRoYW5kbGVCbHVyOiBmdW5jdGlvbihldmVudCkge1xuXHRcdGlmICghdGhpcy5fY29udHJvbElzRm9jdXNlZCkgcmV0dXJuO1xuXHRcdHRoaXMuX2NvbnRyb2xJc0ZvY3VzZWQgPSBmYWxzZTtcblx0XHRjbGVhclRpbWVvdXQodGhpcy5ibHVyVGltZXIpO1xuXHRcdHRoaXMuYmx1clRpbWVyID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcblx0XHRcdGxvZ0V2ZW50KCdibHVyOiBjb250cm9sJyk7XG5cdFx0XHR2YXIgYmx1clN0YXRlID0gdGhpcy5nZXRTdGF0ZUZyb21WYWx1ZSh0aGlzLnN0YXRlLnZhbHVlKTtcblx0XHRcdGJsdXJTdGF0ZS5pc0ZvY3VzZWQgPSBmYWxzZTtcblx0XHRcdGJsdXJTdGF0ZS5pc09wZW4gPSBmYWxzZTtcblx0XHRcdHRoaXMuc2V0U3RhdGUoYmx1clN0YXRlKTtcblx0XHR9LmJpbmQodGhpcyksIDEwMCk7XG5cdH0sXG5cdFxuXHRoYW5kbGVJbnB1dE1vdXNlRG93bjogZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRpZiAodGhpcy5faW5wdXRJc0ZvY3VzZWQpIHtcblx0XHRcdGxvZ0V2ZW50KCdjbGljazogaW5wdXQnKTtcblx0XHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdH1cblx0fSxcblx0XG5cdGhhbmRsZUlucHV0Rm9jdXM6IGZ1bmN0aW9uKGV2ZW50KSB7XG5cdFx0bG9nRXZlbnQoJ2ZvY3VzOiBpbnB1dCcpO1xuXHRcdGNsZWFyVGltZW91dCh0aGlzLmJsdXJUaW1lcik7XG5cdFx0dGhpcy5faW5wdXRJc0ZvY3VzZWQgPSB0cnVlO1xuXHR9LFxuXHRcblx0aGFuZGxlSW5wdXRCbHVyOiBmdW5jdGlvbihldmVudCkge1xuXHRcdGxvZ0V2ZW50KCdibHVyOiBpbnB1dCcpO1xuXHRcdHRoaXMuX2lucHV0SXNGb2N1c2VkID0gZmFsc2U7XG5cdH0sXG5cdFxuXHRoYW5kbGVJbnB1dENoYW5nZTogZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRpZiAodGhpcy5wcm9wcy5hc3luY09wdGlvbnMpIHtcblx0XHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0XHRpc0xvYWRpbmc6IHRydWUsXG5cdFx0XHRcdGlucHV0VmFsdWU6IGV2ZW50LnRhcmdldC52YWx1ZVxuXHRcdFx0fSk7XG5cdFx0XHR0aGlzLmxvYWRBc3luY09wdGlvbnMoZXZlbnQudGFyZ2V0LnZhbHVlLCB7XG5cdFx0XHRcdGlzTG9hZGluZzogZmFsc2UsXG5cdFx0XHRcdGlzT3BlbjogdHJ1ZVxuXHRcdFx0fSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0XHRpc09wZW46IHRydWUsXG5cdFx0XHRcdGlucHV0VmFsdWU6IGV2ZW50LnRhcmdldC52YWx1ZVxuXHRcdFx0fSk7XG5cdFx0fVxuXHR9LFxuXHRcblx0YXV0b2xvYWRBc3luY09wdGlvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMubG9hZEFzeW5jT3B0aW9ucygnJywge30sIGZ1bmN0aW9uKCkge30pO1xuXHR9LFxuXHRcblx0bG9hZEFzeW5jT3B0aW9uczogZnVuY3Rpb24oaW5wdXQsIHN0YXRlKSB7XG5cdFx0XG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPD0gaW5wdXQubGVuZ3RoOyBpKyspIHtcblx0XHRcdHZhciBjYWNoZUtleSA9IGlucHV0LnNsaWNlKDAsIGkpO1xuXHRcdFx0aWYgKHRoaXMuX29wdGlvbnNDYWNoZVtjYWNoZUtleV0gJiYgKGlucHV0ID09PSBjYWNoZUtleSB8fCB0aGlzLl9vcHRpb25zQ2FjaGVbY2FjaGVLZXldLmNvbXBsZXRlKSkge1xuXHRcdFx0XHR0aGlzLnNldFN0YXRlKF8uZXh0ZW5kKHtcblx0XHRcdFx0XHRvcHRpb25zOiB0aGlzLl9vcHRpb25zQ2FjaGVbY2FjaGVLZXldLm9wdGlvbnNcblx0XHRcdFx0fSwgc3RhdGUpKTtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRcblx0XHR2YXIgdGhpc1JlcXVlc3RJZCA9IHRoaXMuX2N1cnJlbnRSZXF1ZXN0SWQgPSByZXF1ZXN0SWQrKztcblx0XHRcblx0XHR0aGlzLnByb3BzLmFzeW5jT3B0aW9ucyhpbnB1dCwgZnVuY3Rpb24oZXJyLCBkYXRhKSB7XG5cdFx0XHRcblx0XHRcdHRoaXMuX29wdGlvbnNDYWNoZVtpbnB1dF0gPSBkYXRhO1xuXHRcdFx0XG5cdFx0XHRpZiAodGhpc1JlcXVlc3RJZCAhPT0gdGhpcy5fY3VycmVudFJlcXVlc3RJZCkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHRcblx0XHRcdHRoaXMuc2V0U3RhdGUoXy5leHRlbmQoe1xuXHRcdFx0XHRvcHRpb25zOiBkYXRhLm9wdGlvbnNcblx0XHRcdH0sIHN0YXRlKSk7XG5cdFx0XHRcblx0XHR9LmJpbmQodGhpcykpO1xuXHRcdFxuXHR9LFxuXHRcblx0ZmlsdGVyT3B0aW9uczogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIF8uZmlsdGVyKHRoaXMuc3RhdGUub3B0aW9ucywgdGhpcy5maWx0ZXJPcHRpb24sIHRoaXMpO1xuXHR9LFxuXHRcblx0ZmlsdGVyT3B0aW9uOiBmdW5jdGlvbihvcCkge1xuXHRcdHJldHVybiAoXG5cdFx0XHQhdGhpcy5zdGF0ZS5pbnB1dFZhbHVlXG5cdFx0XHR8fCBvcC52YWx1ZS50b0xvd2VyQ2FzZSgpLmluZGV4T2YodGhpcy5zdGF0ZS5pbnB1dFZhbHVlLnRvTG93ZXJDYXNlKCkpID49IDBcblx0XHRcdHx8IG9wLmxhYmVsLnRvTG93ZXJDYXNlKCkuaW5kZXhPZih0aGlzLnN0YXRlLmlucHV0VmFsdWUudG9Mb3dlckNhc2UoKSkgPj0gMFxuXHRcdCk7XG5cdH0sXG5cdFxuXHRzZWxlY3RPcHRpb246IGZ1bmN0aW9uKG9wdGlvbikge1xuXHRcdHRoaXMuc2V0VmFsdWUob3B0aW9uKTtcblx0XHR0aGlzLnJlZnMuY29udHJvbC5nZXRET01Ob2RlKCkuZm9jdXMoKTtcblx0fSxcblx0XG5cdHNldFZhbHVlOiBmdW5jdGlvbihvcHRpb24pIHtcblx0XHR2YXIgbmV3U3RhdGUgPSB0aGlzLmdldFN0YXRlRnJvbVZhbHVlKG9wdGlvbik7XG5cdFx0bmV3U3RhdGUuaXNPcGVuID0gZmFsc2U7XG5cdFx0dGhpcy5zZXRTdGF0ZShuZXdTdGF0ZSk7XG5cdH0sXG5cdFxuXHRzZWxlY3RGb2N1c2VkT3B0aW9uOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5zZXRWYWx1ZSh0aGlzLnN0YXRlLmZvY3VzZWRPcHRpb24pO1xuXHR9LFxuXHRcblx0Y2xlYXJWYWx1ZTogZnVuY3Rpb24oZXZlbnQpIHtcblx0XHRsb2dFdmVudCgnY2xlYXIgdmFsdWUnKTtcblx0XHR0aGlzLnNldFZhbHVlKG51bGwpO1xuXHR9LFxuXHRcblx0Y2xvc2VPbkVzY2FwZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5zZXRWYWx1ZSh0aGlzLnN0YXRlLnZhbHVlKTtcblx0fSxcblx0XG5cdGZvY3VzT3B0aW9uOiBmdW5jdGlvbihvcCkge1xuXHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0Zm9jdXNlZE9wdGlvbjogb3Bcblx0XHR9KTtcblx0fSxcblx0XG5cdHVuZm9jdXNPcHRpb246IGZ1bmN0aW9uKG9wKSB7XG5cdFx0aWYgKHRoaXMuc3RhdGUuZm9jdXNlZE9wdGlvbiA9PT0gb3ApIHtcblx0XHRcdHRoaXMuc2V0U3RhdGUoe1xuXHRcdFx0XHRmb2N1c2VkT3B0aW9uOiBudWxsXG5cdFx0XHR9KTtcblx0XHR9XG5cdH0sXG5cdFxuXHRmb2N1c05leHRPcHRpb246IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuZm9jdXNBZGphY2VudE9wdGlvbignbmV4dCcpO1xuXHR9LFxuXHRcblx0Zm9jdXNQcmV2aW91c09wdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5mb2N1c0FkamFjZW50T3B0aW9uKCdwcmV2aW91cycpO1xuXHR9LFxuXHRcblx0Zm9jdXNBZGphY2VudE9wdGlvbjogZnVuY3Rpb24oZGlyKSB7XG5cdFx0XG5cdFx0aWYgKCF0aGlzLnN0YXRlLmlzT3Blbikge1xuXHRcdFx0dGhpcy5zZXRTdGF0ZSh7XG5cdFx0XHRcdGlzT3BlbjogdHJ1ZSxcblx0XHRcdFx0aW5wdXRWYWx1ZTogJydcblx0XHRcdH0pO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRcblx0XHR2YXIgb3BzID0gdGhpcy5maWx0ZXJPcHRpb25zKCk7XG5cdFx0XG5cdFx0aWYgKCFvcHMubGVuZ3RoKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdFxuXHRcdHZhciBmb2N1c2VkSW5kZXggPSAtMTtcblx0XHRcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IG9wcy5sZW5ndGg7IGkrKykge1xuXHRcdFx0aWYgKHRoaXMuc3RhdGUuZm9jdXNlZE9wdGlvbiA9PT0gb3BzW2ldKSB7XG5cdFx0XHRcdGZvY3VzZWRJbmRleCA9IGk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRcblx0XHR2YXIgZm9jdXNlZE9wdGlvbiA9IG9wc1swXTtcblx0XHRcblx0XHRpZiAoZGlyID09PSAnbmV4dCcgJiYgZm9jdXNlZEluZGV4ID4gLTEgJiYgZm9jdXNlZEluZGV4IDwgb3BzLmxlbmd0aCAtIDEpIHtcblx0XHRcdGZvY3VzZWRPcHRpb24gPSBvcHNbZm9jdXNlZEluZGV4ICsgMV07XG5cdFx0fSBlbHNlIGlmIChkaXIgPT09ICdwcmV2aW91cycpIHtcblx0XHRcdGlmIChmb2N1c2VkSW5kZXggPiAwKSB7XG5cdFx0XHRcdGZvY3VzZWRPcHRpb24gPSBvcHNbZm9jdXNlZEluZGV4IC0gMV07XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRmb2N1c2VkT3B0aW9uID0gb3BzW29wcy5sZW5ndGggLSAxXTtcblx0XHRcdH1cblx0XHR9XG5cdFx0XG5cdFx0dGhpcy5zZXRTdGF0ZSh7XG5cdFx0XHRmb2N1c2VkT3B0aW9uOiBmb2N1c2VkT3B0aW9uXG5cdFx0fSk7XG5cdFx0XG5cdH0sXG5cdFxuXHRidWlsZE1lbnU6IGZ1bmN0aW9uKCkge1xuXHRcdFxuXHRcdHZhciBvcHMgPSB7fTtcblx0XHRcblx0XHRfLmVhY2godGhpcy5maWx0ZXJPcHRpb25zKCksIGZ1bmN0aW9uKG9wKSB7XG5cdFx0XHRcblx0XHRcdHZhciBvcHRpb25DbGFzcyA9IGNsYXNzZXMoe1xuXHRcdFx0XHQnU2VsZWN0LW9wdGlvbic6IHRydWUsXG5cdFx0XHRcdCdpcy1mb2N1c2VkJzogdGhpcy5zdGF0ZS5mb2N1c2VkT3B0aW9uID09PSBvcFxuXHRcdFx0fSk7XG5cdFx0XHRcblx0XHRcdHZhciBtb3VzZUVudGVyID0gdGhpcy5mb2N1c09wdGlvbi5iaW5kKHRoaXMsIG9wKSxcblx0XHRcdFx0bW91c2VMZWF2ZSA9IHRoaXMudW5mb2N1c09wdGlvbi5iaW5kKHRoaXMsIG9wKSxcblx0XHRcdFx0bW91c2VEb3duID0gdGhpcy5zZWxlY3RPcHRpb24uYmluZCh0aGlzLCBvcCk7XG5cdFx0XHRcblx0XHRcdG9wc1tvcC52YWx1ZV0gPSBSZWFjdC5ET00uZGl2KHtcblx0XHRcdFx0Y2xhc3NOYW1lOiBvcHRpb25DbGFzcyxcblx0XHRcdFx0b25Nb3VzZUVudGVyOiBtb3VzZUVudGVyLFxuXHRcdFx0XHRvbk1vdXNlTGVhdmU6IG1vdXNlTGVhdmUsXG5cdFx0XHRcdG9uTW91c2VEb3duOiBtb3VzZURvd25cblx0XHRcdH0sIG9wLmxhYmVsKTtcblx0XHRcdFxuXHRcdH0sIHRoaXMpO1xuXHRcdFxuXHRcdGlmIChfLmlzRW1wdHkob3BzKSkge1xuXHRcdFx0b3BzLl9ub19vcHMgPSBSZWFjdC5ET00uZGl2KHtjbGFzc05hbWU6IFwiU2VsZWN0LW5vcmVzdWx0c1wifSwgXCJObyByZXN1bHRzIGZvdW5kXCIpO1xuXHRcdH1cblx0XHRcblx0XHRyZXR1cm4gb3BzO1xuXHRcdFxuXHR9LFxuXHRcblx0cmVuZGVyOiBmdW5jdGlvbigpIHtcblx0XHRcblx0XHRsb2dFdmVudCgncmVuZGVyJyk7XG5cdFx0XG5cdFx0dmFyIG1lbnUgPSB0aGlzLnN0YXRlLmlzT3BlbiA/IFJlYWN0LkRPTS5kaXYoeyBjbGFzc05hbWU6IFwiU2VsZWN0LW1lbnVcIiB9LCB0aGlzLmJ1aWxkTWVudSgpKSA6IG51bGw7XG5cdFx0dmFyIGxvYWRpbmcgPSB0aGlzLnN0YXRlLmlzTG9hZGluZyA/IFJlYWN0LkRPTS5zcGFuKHsgY2xhc3NOYW1lOiBcIlNlbGVjdC1sb2FkaW5nXCIgfSkgOiBudWxsO1xuXHRcdHZhciBjbGVhciA9IHRoaXMuc3RhdGUudmFsdWUgPyBSZWFjdC5ET00uc3Bhbih7IGNsYXNzTmFtZTogXCJTZWxlY3QtY2xlYXJcIiwgb25DbGljazogdGhpcy5jbGVhclZhbHVlLCBkYW5nZXJvdXNseVNldElubmVySFRNTDogeyBfX2h0bWw6ICcmdGltZXM7JyB9IH0pIDogbnVsbDtcblx0XHRcblx0XHR2YXIgc2VsZWN0Q2xhc3MgPSBjbGFzc2VzKCdTZWxlY3QnLCB7XG5cdFx0XHQnaXMtb3Blbic6IHRoaXMuc3RhdGUuaXNPcGVuLFxuXHRcdFx0J2lzLWZvY3VzZWQnOiB0aGlzLnN0YXRlLmlzRm9jdXNlZFxuXHRcdH0pO1xuXHRcdFxuXHRcdHJldHVybiBSZWFjdC5ET00uZGl2KHsgY2xhc3NOYW1lOiBzZWxlY3RDbGFzcyB9LCBcblx0XHRcdFJlYWN0LkRPTS5pbnB1dCh7IHR5cGU6IFwiaGlkZGVuXCIsIHJlZjogXCJ2YWx1ZVwiLCBuYW1lOiB0aGlzLnByb3BzLm5hbWUsIHZhbHVlOiB0aGlzLnN0YXRlLnZhbHVlIH0pLCBcblx0XHRcdFJlYWN0LkRPTS5kaXYoeyBjbGFzc05hbWU6IFwiU2VsZWN0LWNvbnRyb2xcIiwgdGFiSW5kZXg6IFwiLTFcIiwgcmVmOiBcImNvbnRyb2xcIiwgb25LZXlEb3duOiB0aGlzLmhhbmRsZUtleURvd24sIG9uTW91c2VEb3duOiB0aGlzLmhhbmRsZU1vdXNlRG93biwgb25Gb2N1czogdGhpcy5oYW5kbGVGb2N1cywgb25CbHVyOiB0aGlzLmhhbmRsZUJsdXIgfSwgXG5cdFx0XHRcdFJlYWN0LkRPTS5pbnB1dCh7IGNsYXNzTmFtZTogXCJTZWxlY3QtaW5wdXRcIiwgcGxhY2Vob2xkZXI6IHRoaXMuc3RhdGUucGxhY2Vob2xkZXIsIHJlZjogXCJpbnB1dFwiLCBvbk1vdXNlRG93bjogdGhpcy5oYW5kbGVJbnB1dE1vdXNlRG93biwgdmFsdWU6IHRoaXMuc3RhdGUuaW5wdXRWYWx1ZSwgb25Gb2N1czogdGhpcy5oYW5kbGVJbnB1dEZvY3VzLCBvbkJsdXI6IHRoaXMuaGFuZGxlSW5wdXRCbHVyLCBvbkNoYW5nZTogdGhpcy5oYW5kbGVJbnB1dENoYW5nZSB9KSwgXG5cdFx0XHRcdFJlYWN0LkRPTS5zcGFuKHsgY2xhc3NOYW1lOiBcIlNlbGVjdC1hcnJvd1wiIH0pLFxuXHRcdFx0XHRsb2FkaW5nLFxuXHRcdFx0XHRjbGVhclxuXHRcdFx0KSwgXG5cdFx0XHRtZW51XG5cdFx0KTtcblx0fVxuXHRcbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNlbGVjdDtcbiJdfQ==
diff --git a/index.html b/index.html
index f570df5866..b36227caee 100644
--- a/index.html
+++ b/index.html
@@ -15,6 +15,10 @@
@@ -20,10 +20,16 @@
Standalone example
-
+
+
diff --git a/standalone.js b/standalone.js
new file mode 100644
index 0000000000..a224c833c7
--- /dev/null
+++ b/standalone.js
@@ -0,0 +1,493 @@
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Select=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o
tag
+ onChange: React.PropTypes.func, // onChange handler: function(newValue) {}
+ className: React.PropTypes.string // className for the outer element
+ },
+
+ getDefaultProps: function() {
+ return {
+ value: undefined,
+ options: [],
+ delimiter: ',',
+ asyncOptions: undefined,
+ autoload: true,
+ placeholder: '',
+ name: undefined,
+ onChange: undefined,
+ className: undefined
+ };
+ },
+
+ getInitialState: function() {
+ return {
+ /*
+ * set by getStateFromValue on componentWillMount:
+ * - value
+ * - values
+ * - inputValue
+ * - placeholder
+ * - focusedOption
+ */
+ options: this.props.options,
+ isFocused: false,
+ isOpen: false,
+ isLoading: false
+ };
+ },
+
+ componentWillMount: function() {
+ this._optionsCache = {};
+ this.setState(this.getStateFromValue(this.props.value));
+
+ if (this.props.asyncOptions && this.props.autoload) {
+ this.autoloadAsyncOptions();
+ }
+ },
+
+ componentWillUnmount: function() {
+ clearTimeout(this._blurTimeout);
+ clearTimeout(this._focusTimeout);
+ },
+
+ componentWillReceiveProps: function(newProps) {
+ if (newProps.value !== this.state.value) {
+ this.setState(this.getStateFromValue(newProps.value));
+ }
+ if (newProps.options !== this.props.options) {
+ this.setState({ options: newProps.options });
+ }
+ },
+
+ componentDidUpdate: function() {
+ if (this._focusAfterUpdate) {
+ clearTimeout(this._blurTimeout);
+ this._focusTimeout = setTimeout(function() {
+ this.refs.input.focus();
+ this._focusAfterUpdate = false;
+ }.bind(this), 50);
+ }
+ },
+
+ initValuesArray: function(values) {
+
+ if (!Array.isArray(values)) {
+ if ('string' === typeof values) {
+ values = values.split(this.props.delimiter);
+ } else {
+ values = values ? [values] : []
+ }
+ };
+
+ return values.map(function(val) {
+ return ('string' === typeof val) ? val = _.findWhere(this.state.options, { value: val }) || { value: val, label: val } : val;
+ }.bind(this));
+
+ },
+
+ getStateFromValue: function(value) {
+
+ var values = this.initValuesArray(value);
+
+ return {
+ value: values.map(function(v) { return v.value }).join(this.props.delimiter),
+ values: values,
+ inputValue: '',
+ placeholder: !this.props.multi && values.length ? values[0].label : this.props.placeholder || 'Select...',
+ focusedOption: !this.props.multi ? values[0] : null
+ };
+
+ },
+
+ setValue: function(value) {
+ this._focusAfterUpdate = true;
+ var newState = this.getStateFromValue(value);
+ newState.isOpen = false;
+ this.fireChangeEvent(newState);
+ this.setState(newState);
+ },
+
+ selectValue: function(value) {
+ this[this.props.multi ? 'addValue' : 'setValue'](value);
+ },
+
+ addValue: function(value) {
+ this.setValue(this.state.values.concat(value));
+ },
+
+ popValue: function() {
+ this.setValue(_.initial(this.state.values));
+ },
+
+ removeValue: function(value) {
+ this.setValue(_.without(this.state.values, value));
+ },
+
+ clearValue: function() {
+ this.setValue(null);
+ },
+
+ resetValue: function() {
+ this.setValue(this.state.value);
+ },
+
+ fireChangeEvent: function(newState) {
+ if (newState.value !== this.state.value && this.props.onChange) {
+ this.props.onChange(newState.value, newState.values);
+ }
+ },
+
+ handleMouseDown: function(event) {
+ event.stopPropagation();
+ event.preventDefault();
+ if (this.state.isFocused) {
+ this.setState({
+ isOpen: true
+ });
+ } else {
+ this._openAfterFocus = true;
+ this.refs.input.focus();
+ }
+ },
+
+ handleInputFocus: function() {
+ this.setState({
+ isFocused: true,
+ isOpen: this.state.isOpen || this._openAfterFocus
+ });
+ this._openAfterFocus = false;
+ },
+
+ handleInputBlur: function(event) {
+ this._blurTimeout = setTimeout(function() {
+ if (this._focusAfterUpdate) return;
+ this.setState({
+ isOpen: false,
+ isFocused: false
+ });
+ }.bind(this), 50);
+ },
+
+ handleKeyDown: function(event) {
+
+ switch (event.keyCode) {
+
+ case 8: // backspace
+ if (!this.state.inputValue) {
+ this.popValue();
+ }
+ return;
+ break;
+
+ case 9: // tab
+ if (event.shiftKey || !this.state.isOpen || !this.state.focusedOption) {
+ return;
+ }
+ this.selectFocusedOption();
+ break;
+
+ case 13: // enter
+ this.selectFocusedOption();
+ break;
+
+ case 27: // escape
+ if (this.state.isOpen) {
+ this.resetValue();
+ } else {
+ this.clearValue();
+ }
+ break;
+
+ case 38: // up
+ this.focusPreviousOption();
+ break;
+
+ case 40: // down
+ this.focusNextOption();
+ break;
+
+ default: return;
+ }
+
+ event.preventDefault();
+
+ },
+
+ handleInputChange: function(event) {
+ if (this.props.asyncOptions) {
+ this.setState({
+ isLoading: true,
+ inputValue: event.target.value
+ });
+ this.loadAsyncOptions(event.target.value, {
+ isLoading: false,
+ isOpen: true
+ });
+ } else {
+ this.setState({
+ isOpen: true,
+ inputValue: event.target.value
+ });
+ }
+ },
+
+ autoloadAsyncOptions: function() {
+ this.loadAsyncOptions('', {}, function() {});
+ },
+
+ loadAsyncOptions: function(input, state) {
+
+ for (var i = 0; i <= input.length; i++) {
+ var cacheKey = input.slice(0, i);
+ if (this._optionsCache[cacheKey] && (input === cacheKey || this._optionsCache[cacheKey].complete)) {
+ this.setState(_.extend({
+ options: this._optionsCache[cacheKey].options
+ }, state));
+ return;
+ }
+ }
+
+ var thisRequestId = this._currentRequestId = requestId++;
+
+ this.props.asyncOptions(input, function(err, data) {
+
+ this._optionsCache[input] = data;
+
+ if (thisRequestId !== this._currentRequestId) {
+ return;
+ }
+
+ this.setState(_.extend({
+ options: data.options
+ }, state));
+
+ }.bind(this));
+
+ },
+
+ filterOptions: function() {
+ var values = this.state.values.map(function(i) {
+ return i.value;
+ });
+ var filterOption = function(op) {
+ if (this.props.multi && _.contains(values, op.value)) return false;
+ return (
+ !this.state.inputValue
+ || op.value.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
+ || op.label.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
+ );
+ }
+ return _.filter(this.state.options, filterOption, this);
+ },
+
+ selectFocusedOption: function() {
+ return this.selectValue(this.state.focusedOption);
+ },
+
+ focusOption: function(op) {
+ this.setState({
+ focusedOption: op
+ });
+ },
+
+ focusNextOption: function() {
+ this.focusAdjacentOption('next');
+ },
+
+ focusPreviousOption: function() {
+ this.focusAdjacentOption('previous');
+ },
+
+ focusAdjacentOption: function(dir) {
+
+ var ops = this.filterOptions();
+
+ if (!this.state.isOpen) {
+ this.setState({
+ isOpen: true,
+ inputValue: '',
+ focusedOption: this.state.focusedOption || ops[dir === 'next' ? 0 : ops.length - 1]
+ });
+ return;
+ }
+
+ if (!ops.length) {
+ return;
+ }
+
+ var focusedIndex = -1;
+
+ for (var i = 0; i < ops.length; i++) {
+ if (this.state.focusedOption === ops[i]) {
+ focusedIndex = i;
+ break;
+ }
+ }
+
+ var focusedOption = ops[0];
+
+ if (dir === 'next' && focusedIndex > -1 && focusedIndex < ops.length - 1) {
+ focusedOption = ops[focusedIndex + 1];
+ } else if (dir === 'previous') {
+ if (focusedIndex > 0) {
+ focusedOption = ops[focusedIndex - 1];
+ } else {
+ focusedOption = ops[ops.length - 1];
+ }
+ }
+
+ this.setState({
+ focusedOption: focusedOption
+ });
+
+ },
+
+ unfocusOption: function(op) {
+ if (this.state.focusedOption === op) {
+ this.setState({
+ focusedOption: null
+ });
+ }
+ },
+
+ buildMenu: function() {
+
+ var ops = _.map(this.filterOptions(), function(op) {
+
+ var optionClass = classes({
+ 'Select-option': true,
+ 'is-focused': this.state.focusedOption === op
+ });
+
+ var mouseEnter = this.focusOption.bind(this, op),
+ mouseLeave = this.unfocusOption.bind(this, op),
+ mouseDown = this.selectValue.bind(this, op);
+
+ return React.createElement("div", {key: 'option-' + op.value, className: optionClass, onMouseEnter: mouseEnter, onMouseLeave: mouseLeave, onMouseDown: mouseDown}, op.label);
+
+ }, this);
+
+ return ops.length ? ops : React.createElement('div', { className: "Select-noresults" }, "No results found");
+
+ },
+
+ render: function() {
+
+ var selectClass = classes('Select', this.props.className, {
+ 'is-multi': this.props.multi,
+ 'is-open': this.state.isOpen,
+ 'is-focused': this.state.isFocused,
+ 'is-loading': this.state.isLoading,
+ 'has-value': this.state.value
+ });
+
+ var value = [];
+
+ if (this.props.multi) {
+ this.state.values.forEach(function(val) {
+ props = _.extend({
+ key: val.value,
+ onRemove: this.removeValue.bind(this, val)
+ }, val);
+ value.push(React.createElement(Value, props));
+ }, this);
+ }
+
+ if (!this.state.inputValue && (!this.props.multi || !value.length)) {
+ value.push(React.createElement("div", {className: "Select-placeholder", key: "placeholder"}, this.state.placeholder));
+ }
+
+ var loading = this.state.isLoading ? React.createElement('span', { className: "Select-loading" }) : null;
+ var clear = this.state.value ? React.createElement("span", {className: "Select-clear", onMouseDown: this.clearValue, dangerouslySetInnerHTML: { __html: '×'}}) : null;
+ var menu = this.state.isOpen ? React.createElement("div", {className: "Select-menu"}, this.buildMenu()) : null;
+
+ return (
+ React.createElement("div", {ref: "wrapper", className: selectClass},
+ React.createElement("input", {type: "hidden", ref: "value", name: this.props.name, value: this.state.value}),
+ React.createElement("div", {className: "Select-control", ref: "control", onKeyDown: this.handleKeyDown, onMouseDown: this.handleMouseDown},
+ value,
+ React.createElement(Input, {className: "Select-input", tabIndex: this.props.tabIndex, ref: "input", value: this.state.inputValue, onFocus: this.handleInputFocus, onBlur: this.handleInputBlur, onChange: this.handleInputChange, minWidth: "5"}),
+ React.createElement("span", {className: "Select-arrow"}),
+ loading,
+ clear
+ ),
+ menu
+ )
+ );
+
+ }
+
+});
+
+module.exports = Select;
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"./value":3,"classnames":2}],2:[function(require,module,exports){
+function classnames() {
+ var args = arguments, classes = [];
+ for (var i = 0; i < args.length; i++) {
+ if (args[i] && 'string' === typeof args[i]) {
+ classes.push(args[i]);
+ } else if ('object' === typeof args[i]) {
+ classes = classes.concat(Object.keys(args[i]).filter(function(cls) {
+ return args[i][cls];
+ }));
+ }
+ }
+ return classes.join(' ') || undefined;
+}
+
+module.exports = classnames;
+
+},{}],3:[function(require,module,exports){
+(function (global){
+var _ = (typeof window !== "undefined" ? window._ : typeof global !== "undefined" ? global._ : null),
+ React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null),
+ classes = require('classnames');
+
+var Option = React.createClass({
+
+ displayName: 'Value',
+
+ propTypes: {
+ label: React.PropTypes.string.isRequired
+ },
+
+ blockEvent: function(event) {
+ event.stopPropagation();
+ },
+
+ render: function() {
+ return React.createElement("div", {className: "Select-item"},
+ React.createElement("span", {className: "Select-item-icon", onMouseDown: this.blockEvent, onClick: this.props.onRemove}, "×"),
+ React.createElement("span", {className: "Select-item-label"}, this.props.label)
+ );
+ }
+
+});
+
+module.exports = Option;
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{"classnames":2}]},{},[1])(1)
+});
\ No newline at end of file
From 4eebe2e6f2164d5e4e7602fa7e446917cec3b375 Mon Sep 17 00:00:00 2001
From: Jed Watson
Date: Sun, 30 Nov 2014 22:49:20 +1100
Subject: [PATCH 13/31] Update 2014-11-30T11:49:12.747Z
---
bundle.js | 63 +++++++++++++++++++++++++++++++++++----------------
common.js | 2 +-
standalone.js | 63 +++++++++++++++++++++++++++++++++++----------------
3 files changed, 89 insertions(+), 39 deletions(-)
diff --git a/bundle.js b/bundle.js
index 2746df34f2..cba59a06a3 100644
--- a/bundle.js
+++ b/bundle.js
@@ -48,7 +48,7 @@ var _ = require('underscore'),
React = require('react'),
Input = require('react-input-autosize'),
classes = require('classnames'),
- Value = require('./value');
+ Value = require('./Value');
var requestId = 0;
@@ -89,6 +89,7 @@ var Select = React.createClass({
* set by getStateFromValue on componentWillMount:
* - value
* - values
+ * - filteredOptions
* - inputValue
* - placeholder
* - focusedOption
@@ -102,6 +103,7 @@ var Select = React.createClass({
componentWillMount: function() {
this._optionsCache = {};
+ this._optionsFilterString = '';
this.setState(this.getStateFromValue(this.props.value));
if (this.props.asyncOptions && this.props.autoload) {
@@ -118,8 +120,11 @@ var Select = React.createClass({
if (newProps.value !== this.state.value) {
this.setState(this.getStateFromValue(newProps.value));
}
- if (newProps.options !== this.props.options) {
- this.setState({ options: newProps.options });
+ if (JSON.stringify(newProps.options) !== JSON.stringify(this.props.options)) {
+ this.setState({
+ options: newProps.options,
+ filteredOptions: this.filterOptions(newProps.options)
+ });
}
},
@@ -151,14 +156,19 @@ var Select = React.createClass({
getStateFromValue: function(value) {
- var values = this.initValuesArray(value);
+ // reset internal filter string
+ this._optionsFilterString = '';
+
+ var values = this.initValuesArray(value),
+ filteredOptions = this.filterOptions(this.state.options, values);
return {
value: values.map(function(v) { return v.value }).join(this.props.delimiter),
values: values,
inputValue: '',
+ filteredOptions: filteredOptions,
placeholder: !this.props.multi && values.length ? values[0].label : this.props.placeholder || 'Select...',
- focusedOption: !this.props.multi ? values[0] : null
+ focusedOption: !this.props.multi && values.length ? values[0] : filteredOptions[0]
};
},
@@ -278,6 +288,11 @@ var Select = React.createClass({
},
handleInputChange: function(event) {
+
+ // assign an internal variable because we need to use
+ // the latest value before setState() has completed.
+ this._optionsFilterString = event.target.value;
+
if (this.props.asyncOptions) {
this.setState({
isLoading: true,
@@ -288,11 +303,15 @@ var Select = React.createClass({
isOpen: true
});
} else {
+ var filteredOptions = this.filterOptions(this.state.options);
this.setState({
isOpen: true,
- inputValue: event.target.value
+ inputValue: event.target.value,
+ filteredOptions: filteredOptions,
+ focusedOption: _.contains(filteredOptions, this.state.focusedOption) ? this.state.focusedOption : filteredOptions[0]
});
}
+
},
autoloadAsyncOptions: function() {
@@ -304,8 +323,10 @@ var Select = React.createClass({
for (var i = 0; i <= input.length; i++) {
var cacheKey = input.slice(0, i);
if (this._optionsCache[cacheKey] && (input === cacheKey || this._optionsCache[cacheKey].complete)) {
+ var options = this._optionsCache[cacheKey].options;
this.setState(_.extend({
- options: this._optionsCache[cacheKey].options
+ options: options,
+ filteredOptions: this.filterOptions(options)
}, state));
return;
}
@@ -322,26 +343,28 @@ var Select = React.createClass({
}
this.setState(_.extend({
- options: data.options
+ options: data.options,
+ filteredOptions: this.filterOptions(data.options)
}, state));
}.bind(this));
},
- filterOptions: function() {
- var values = this.state.values.map(function(i) {
+ filterOptions: function(options, values) {
+ var filterValue = this._optionsFilterString;
+ var exclude = (values || this.state.values).map(function(i) {
return i.value;
});
var filterOption = function(op) {
- if (this.props.multi && _.contains(values, op.value)) return false;
+ if (this.props.multi && _.contains(exclude, op.value)) return false;
return (
- !this.state.inputValue
- || op.value.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
- || op.label.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
+ !filterValue
+ || op.value.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0
+ || op.label.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0
);
}
- return _.filter(this.state.options, filterOption, this);
+ return _.filter(options, filterOption, this);
},
selectFocusedOption: function() {
@@ -364,7 +387,7 @@ var Select = React.createClass({
focusAdjacentOption: function(dir) {
- var ops = this.filterOptions();
+ var ops = this.state.filteredOptions;
if (!this.state.isOpen) {
this.setState({
@@ -416,11 +439,13 @@ var Select = React.createClass({
buildMenu: function() {
- var ops = _.map(this.filterOptions(), function(op) {
+ var focusedValue = this.state.focusedOption ? this.state.focusedOption.value : null;
+
+ var ops = _.map(this.state.filteredOptions, function(op) {
var optionClass = classes({
'Select-option': true,
- 'is-focused': this.state.focusedOption === op
+ 'is-focused': focusedValue === op.value
});
var mouseEnter = this.focusOption.bind(this, op),
@@ -485,4 +510,4 @@ var Select = React.createClass({
module.exports = Select;
-},{"./value":2,"classnames":1,"react":undefined,"react-input-autosize":undefined,"underscore":undefined}]},{},[]);
+},{"./Value":2,"classnames":1,"react":undefined,"react-input-autosize":undefined,"underscore":undefined}]},{},[]);
diff --git a/common.js b/common.js
index 46d8123ef7..a56f670432 100644
--- a/common.js
+++ b/common.js
@@ -18388,7 +18388,7 @@ var AutosizeInput = React.createClass({
module.exports = AutosizeInput;
-},{"react":undefined}],"react":[function(require,module,exports){
+},{"react":"react"}],"react":[function(require,module,exports){
module.exports = require('./lib/React');
},{"./lib/React":29}],"underscore":[function(require,module,exports){
diff --git a/standalone.js b/standalone.js
index a224c833c7..8c8cc16f53 100644
--- a/standalone.js
+++ b/standalone.js
@@ -4,7 +4,7 @@ var _ = (typeof window !== "undefined" ? window._ : typeof global !== "undefined
React = (typeof window !== "undefined" ? window.React : typeof global !== "undefined" ? global.React : null),
Input = (typeof window !== "undefined" ? window.AutosizeInput : typeof global !== "undefined" ? global.AutosizeInput : null),
classes = require('classnames'),
- Value = require('./value');
+ Value = require('./Value');
var requestId = 0;
@@ -45,6 +45,7 @@ var Select = React.createClass({
* set by getStateFromValue on componentWillMount:
* - value
* - values
+ * - filteredOptions
* - inputValue
* - placeholder
* - focusedOption
@@ -58,6 +59,7 @@ var Select = React.createClass({
componentWillMount: function() {
this._optionsCache = {};
+ this._optionsFilterString = '';
this.setState(this.getStateFromValue(this.props.value));
if (this.props.asyncOptions && this.props.autoload) {
@@ -74,8 +76,11 @@ var Select = React.createClass({
if (newProps.value !== this.state.value) {
this.setState(this.getStateFromValue(newProps.value));
}
- if (newProps.options !== this.props.options) {
- this.setState({ options: newProps.options });
+ if (JSON.stringify(newProps.options) !== JSON.stringify(this.props.options)) {
+ this.setState({
+ options: newProps.options,
+ filteredOptions: this.filterOptions(newProps.options)
+ });
}
},
@@ -107,14 +112,19 @@ var Select = React.createClass({
getStateFromValue: function(value) {
- var values = this.initValuesArray(value);
+ // reset internal filter string
+ this._optionsFilterString = '';
+
+ var values = this.initValuesArray(value),
+ filteredOptions = this.filterOptions(this.state.options, values);
return {
value: values.map(function(v) { return v.value }).join(this.props.delimiter),
values: values,
inputValue: '',
+ filteredOptions: filteredOptions,
placeholder: !this.props.multi && values.length ? values[0].label : this.props.placeholder || 'Select...',
- focusedOption: !this.props.multi ? values[0] : null
+ focusedOption: !this.props.multi && values.length ? values[0] : filteredOptions[0]
};
},
@@ -234,6 +244,11 @@ var Select = React.createClass({
},
handleInputChange: function(event) {
+
+ // assign an internal variable because we need to use
+ // the latest value before setState() has completed.
+ this._optionsFilterString = event.target.value;
+
if (this.props.asyncOptions) {
this.setState({
isLoading: true,
@@ -244,11 +259,15 @@ var Select = React.createClass({
isOpen: true
});
} else {
+ var filteredOptions = this.filterOptions(this.state.options);
this.setState({
isOpen: true,
- inputValue: event.target.value
+ inputValue: event.target.value,
+ filteredOptions: filteredOptions,
+ focusedOption: _.contains(filteredOptions, this.state.focusedOption) ? this.state.focusedOption : filteredOptions[0]
});
}
+
},
autoloadAsyncOptions: function() {
@@ -260,8 +279,10 @@ var Select = React.createClass({
for (var i = 0; i <= input.length; i++) {
var cacheKey = input.slice(0, i);
if (this._optionsCache[cacheKey] && (input === cacheKey || this._optionsCache[cacheKey].complete)) {
+ var options = this._optionsCache[cacheKey].options;
this.setState(_.extend({
- options: this._optionsCache[cacheKey].options
+ options: options,
+ filteredOptions: this.filterOptions(options)
}, state));
return;
}
@@ -278,26 +299,28 @@ var Select = React.createClass({
}
this.setState(_.extend({
- options: data.options
+ options: data.options,
+ filteredOptions: this.filterOptions(data.options)
}, state));
}.bind(this));
},
- filterOptions: function() {
- var values = this.state.values.map(function(i) {
+ filterOptions: function(options, values) {
+ var filterValue = this._optionsFilterString;
+ var exclude = (values || this.state.values).map(function(i) {
return i.value;
});
var filterOption = function(op) {
- if (this.props.multi && _.contains(values, op.value)) return false;
+ if (this.props.multi && _.contains(exclude, op.value)) return false;
return (
- !this.state.inputValue
- || op.value.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
- || op.label.toLowerCase().indexOf(this.state.inputValue.toLowerCase()) >= 0
+ !filterValue
+ || op.value.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0
+ || op.label.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0
);
}
- return _.filter(this.state.options, filterOption, this);
+ return _.filter(options, filterOption, this);
},
selectFocusedOption: function() {
@@ -320,7 +343,7 @@ var Select = React.createClass({
focusAdjacentOption: function(dir) {
- var ops = this.filterOptions();
+ var ops = this.state.filteredOptions;
if (!this.state.isOpen) {
this.setState({
@@ -372,11 +395,13 @@ var Select = React.createClass({
buildMenu: function() {
- var ops = _.map(this.filterOptions(), function(op) {
+ var focusedValue = this.state.focusedOption ? this.state.focusedOption.value : null;
+
+ var ops = _.map(this.state.filteredOptions, function(op) {
var optionClass = classes({
'Select-option': true,
- 'is-focused': this.state.focusedOption === op
+ 'is-focused': focusedValue === op.value
});
var mouseEnter = this.focusOption.bind(this, op),
@@ -442,7 +467,7 @@ var Select = React.createClass({
module.exports = Select;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./value":3,"classnames":2}],2:[function(require,module,exports){
+},{"./Value":3,"classnames":2}],2:[function(require,module,exports){
function classnames() {
var args = arguments, classes = [];
for (var i = 0; i < args.length; i++) {
From c0ac8fff5724e68b842d50b881ba06dad280a0c6 Mon Sep 17 00:00:00 2001
From: Jed Watson
Date: Mon, 1 Dec 2014 21:03:29 +1100
Subject: [PATCH 14/31] Update 2014-12-01T10:03:29.410Z
---
bundle.js | 16 +++++++++++++---
standalone.js | 16 +++++++++++++---
2 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/bundle.js b/bundle.js
index cba59a06a3..226b4c22b7 100644
--- a/bundle.js
+++ b/bundle.js
@@ -197,7 +197,12 @@ var Select = React.createClass({
this.setValue(_.without(this.state.values, value));
},
- clearValue: function() {
+ clearValue: function(event) {
+ // if the event was triggered by a mousedown and not the primary
+ // button, ignore it.
+ if (event && event.type == 'mousedown' && event.button !== 0) {
+ return;
+ }
this.setValue(null);
},
@@ -212,6 +217,11 @@ var Select = React.createClass({
},
handleMouseDown: function(event) {
+ // if the event was triggered by a mousedown and not the primary
+ // button, ignore it.
+ if (event.type == 'mousedown' && event.button !== 0) {
+ return;
+ }
event.stopPropagation();
event.preventDefault();
if (this.state.isFocused) {
@@ -486,8 +496,8 @@ var Select = React.createClass({
value.push(React.createElement("div", {className: "Select-placeholder", key: "placeholder"}, this.state.placeholder));
}
- var loading = this.state.isLoading ? React.createElement('span', { className: "Select-loading" }) : null;
- var clear = this.state.value ? React.createElement("span", {className: "Select-clear", onMouseDown: this.clearValue, dangerouslySetInnerHTML: { __html: '×'}}) : null;
+ var loading = this.state.isLoading ? React.createElement("span", {className: "Select-loading", 'aria-hidden': "true"}) : null;
+ var clear = this.state.value ? React.createElement("span", {className: "Select-clear", 'aria-label': "Clear value", onMouseDown: this.clearValue, dangerouslySetInnerHTML: { __html: '×'}}) : null;
var menu = this.state.isOpen ? React.createElement("div", {className: "Select-menu"}, this.buildMenu()) : null;
return (
diff --git a/standalone.js b/standalone.js
index 8c8cc16f53..5798717592 100644
--- a/standalone.js
+++ b/standalone.js
@@ -153,7 +153,12 @@ var Select = React.createClass({
this.setValue(_.without(this.state.values, value));
},
- clearValue: function() {
+ clearValue: function(event) {
+ // if the event was triggered by a mousedown and not the primary
+ // button, ignore it.
+ if (event && event.type == 'mousedown' && event.button !== 0) {
+ return;
+ }
this.setValue(null);
},
@@ -168,6 +173,11 @@ var Select = React.createClass({
},
handleMouseDown: function(event) {
+ // if the event was triggered by a mousedown and not the primary
+ // button, ignore it.
+ if (event.type == 'mousedown' && event.button !== 0) {
+ return;
+ }
event.stopPropagation();
event.preventDefault();
if (this.state.isFocused) {
@@ -442,8 +452,8 @@ var Select = React.createClass({
value.push(React.createElement("div", {className: "Select-placeholder", key: "placeholder"}, this.state.placeholder));
}
- var loading = this.state.isLoading ? React.createElement('span', { className: "Select-loading" }) : null;
- var clear = this.state.value ? React.createElement("span", {className: "Select-clear", onMouseDown: this.clearValue, dangerouslySetInnerHTML: { __html: '×'}}) : null;
+ var loading = this.state.isLoading ? React.createElement("span", {className: "Select-loading", 'aria-hidden': "true"}) : null;
+ var clear = this.state.value ? React.createElement("span", {className: "Select-clear", 'aria-label': "Clear value", onMouseDown: this.clearValue, dangerouslySetInnerHTML: { __html: '×'}}) : null;
var menu = this.state.isOpen ? React.createElement("div", {className: "Select-menu"}, this.buildMenu()) : null;
return (
From dcb62a441aa3c7608a14bf6847adbff9e6145771 Mon Sep 17 00:00:00 2001
From: Jed Watson
Date: Tue, 9 Dec 2014 00:02:53 +1100
Subject: [PATCH 15/31] Update 2014-12-08T13:02:46.054Z
---
bundle.js | 19 +++++++++++++------
standalone.js | 19 +++++++++++++------
2 files changed, 26 insertions(+), 12 deletions(-)
diff --git a/bundle.js b/bundle.js
index 226b4c22b7..40dbca35e4 100644
--- a/bundle.js
+++ b/bundle.js
@@ -66,7 +66,9 @@ var Select = React.createClass({
placeholder: React.PropTypes.string, // field placeholder, displayed when there's no value
name: React.PropTypes.string, // field name, for hidden tag
onChange: React.PropTypes.func, // onChange handler: function(newValue) {}
- className: React.PropTypes.string // className for the outer element
+ className: React.PropTypes.string, // className for the outer element
+ matchPos: React.PropTypes.string, // (any|start) match the start or entire string when filtering
+ matchProp: React.PropTypes.string // (any|label|value) which option property to filter on
},
getDefaultProps: function() {
@@ -79,7 +81,9 @@ var Select = React.createClass({
placeholder: '',
name: undefined,
onChange: undefined,
- className: undefined
+ className: undefined,
+ matchPos: 'any',
+ matchProp: 'any'
};
},
@@ -368,10 +372,13 @@ var Select = React.createClass({
});
var filterOption = function(op) {
if (this.props.multi && _.contains(exclude, op.value)) return false;
- return (
- !filterValue
- || op.value.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0
- || op.label.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0
+ if (this.props.filterOption) return this.props.filterOption.call(this, option, filterValue);
+ return !filterValue || (this.props.matchPos === 'start') ? (
+ (this.props.matchProp !== 'label' && op.value.toLowerCase().substr(0, filterValue.length) === filterValue) ||
+ (this.props.matchProp !== 'value' && op.label.toLowerCase().substr(0, filterValue.length) === filterValue)
+ ) : (
+ (this.props.matchProp !== 'label' && op.value.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0) ||
+ (this.props.matchProp !== 'value' && op.label.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0)
);
}
return _.filter(options, filterOption, this);
diff --git a/standalone.js b/standalone.js
index 5798717592..887af088c1 100644
--- a/standalone.js
+++ b/standalone.js
@@ -22,7 +22,9 @@ var Select = React.createClass({
placeholder: React.PropTypes.string, // field placeholder, displayed when there's no value
name: React.PropTypes.string, // field name, for hidden tag
onChange: React.PropTypes.func, // onChange handler: function(newValue) {}
- className: React.PropTypes.string // className for the outer element
+ className: React.PropTypes.string, // className for the outer element
+ matchPos: React.PropTypes.string, // (any|start) match the start or entire string when filtering
+ matchProp: React.PropTypes.string // (any|label|value) which option property to filter on
},
getDefaultProps: function() {
@@ -35,7 +37,9 @@ var Select = React.createClass({
placeholder: '',
name: undefined,
onChange: undefined,
- className: undefined
+ className: undefined,
+ matchPos: 'any',
+ matchProp: 'any'
};
},
@@ -324,10 +328,13 @@ var Select = React.createClass({
});
var filterOption = function(op) {
if (this.props.multi && _.contains(exclude, op.value)) return false;
- return (
- !filterValue
- || op.value.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0
- || op.label.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0
+ if (this.props.filterOption) return this.props.filterOption.call(this, option, filterValue);
+ return !filterValue || (this.props.matchPos === 'start') ? (
+ (this.props.matchProp !== 'label' && op.value.toLowerCase().substr(0, filterValue.length) === filterValue) ||
+ (this.props.matchProp !== 'value' && op.label.toLowerCase().substr(0, filterValue.length) === filterValue)
+ ) : (
+ (this.props.matchProp !== 'label' && op.value.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0) ||
+ (this.props.matchProp !== 'value' && op.label.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0)
);
}
return _.filter(options, filterOption, this);
From fb6ab8e7370339a65be1fabf8a9d767f0d6b7191 Mon Sep 17 00:00:00 2001
From: Jed Watson
Date: Tue, 9 Dec 2014 22:02:33 +1100
Subject: [PATCH 16/31] Update 2014-12-09T11:02:33.292Z
---
bundle.js | 40 ++++++++++++++++++++++++----------------
index.html | 13 ++++++++++++-
standalone.js | 40 ++++++++++++++++++++++++----------------
3 files changed, 60 insertions(+), 33 deletions(-)
diff --git a/bundle.js b/bundle.js
index 40dbca35e4..5429fb05d5 100644
--- a/bundle.js
+++ b/bundle.js
@@ -33,9 +33,11 @@ var Option = React.createClass({
},
render: function() {
- return React.createElement("div", {className: "Select-item"},
- React.createElement("span", {className: "Select-item-icon", onMouseDown: this.blockEvent, onClick: this.props.onRemove}, "×"),
- React.createElement("span", {className: "Select-item-label"}, this.props.label)
+ return (
+ React.createElement("div", {className: "Select-item"},
+ React.createElement("span", {className: "Select-item-icon", onMouseDown: this.blockEvent, onClick: this.props.onRemove}, "×"),
+ React.createElement("span", {className: "Select-item-label"}, this.props.label)
+ )
);
}
@@ -67,6 +69,8 @@ var Select = React.createClass({
name: React.PropTypes.string, // field name, for hidden tag
onChange: React.PropTypes.func, // onChange handler: function(newValue) {}
className: React.PropTypes.string, // className for the outer element
+ filterOption: React.PropTypes.func, // method to filter a single option: function(option, filterString)
+ filterOptions: React.PropTypes.func, // method to filter the options array: function([options], filterString, [values])
matchPos: React.PropTypes.string, // (any|start) match the start or entire string when filtering
matchProp: React.PropTypes.string // (any|label|value) which option property to filter on
},
@@ -370,18 +374,22 @@ var Select = React.createClass({
var exclude = (values || this.state.values).map(function(i) {
return i.value;
});
- var filterOption = function(op) {
- if (this.props.multi && _.contains(exclude, op.value)) return false;
- if (this.props.filterOption) return this.props.filterOption.call(this, option, filterValue);
- return !filterValue || (this.props.matchPos === 'start') ? (
- (this.props.matchProp !== 'label' && op.value.toLowerCase().substr(0, filterValue.length) === filterValue) ||
- (this.props.matchProp !== 'value' && op.label.toLowerCase().substr(0, filterValue.length) === filterValue)
- ) : (
- (this.props.matchProp !== 'label' && op.value.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0) ||
- (this.props.matchProp !== 'value' && op.label.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0)
- );
+ if (this.props.filterOptions) {
+ return this.props.filterOptions.call(this, options, filterValue, exclude);
+ } else {
+ var filterOption = function(op) {
+ if (this.props.multi && _.contains(exclude, op.value)) return false;
+ if (this.props.filterOption) return this.props.filterOption.call(this, op, filterValue);
+ return !filterValue || (this.props.matchPos === 'start') ? (
+ (this.props.matchProp !== 'label' && op.value.toLowerCase().substr(0, filterValue.length) === filterValue) ||
+ (this.props.matchProp !== 'value' && op.label.toLowerCase().substr(0, filterValue.length) === filterValue)
+ ) : (
+ (this.props.matchProp !== 'label' && op.value.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0) ||
+ (this.props.matchProp !== 'value' && op.label.toLowerCase().indexOf(filterValue.toLowerCase()) >= 0)
+ );
+ }
+ return _.filter(options, filterOption, this);
}
- return _.filter(options, filterOption, this);
},
selectFocusedOption: function() {
@@ -473,7 +481,7 @@ var Select = React.createClass({
}, this);
- return ops.length ? ops : React.createElement('div', { className: "Select-noresults" }, "No results found");
+ return ops.length ? ops : React.createElement("div", {className: "Select-noresults"}, "No results found");
},
@@ -495,7 +503,7 @@ var Select = React.createClass({
key: val.value,
onRemove: this.removeValue.bind(this, val)
}, val);
- value.push(React.createElement(Value, props));
+ value.push(React.createElement(Value, React.__spread({}, props)));
}, this);
}
diff --git a/index.html b/index.html
index cac4af1d45..cfbae419a2 100644
--- a/index.html
+++ b/index.html
@@ -1,12 +1,23 @@
+
React-Select Example
+
+
+
+
+
+
+
+
+
diff --git a/standalone.html b/standalone.html
index 65433b0eaf..9f3f4da54b 100644
--- a/standalone.html
+++ b/standalone.html
@@ -1,7 +1,7 @@