Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7dfd3948a9 | ||
|
|
b3ebab438b | ||
|
|
0070ad353a | ||
|
|
39ce13e9b3 | ||
|
|
6ed8e9d788 | ||
|
|
9eb86c14b4 | ||
|
|
c7a4196413 | ||
|
|
4decc08e53 | ||
|
|
76a30ace67 | ||
|
|
bdf263625d | ||
|
|
8c7bbbfc21 | ||
|
|
15631e02a2 | ||
|
|
1907f72934 | ||
|
|
ba62748217 | ||
|
|
224ace32be | ||
|
|
3ef748abb3 | ||
|
|
3f8b8d754c | ||
|
|
7a18e4e00b | ||
|
|
60ed71459c | ||
|
|
7b39bbaa91 | ||
|
|
2927c4ce76 | ||
|
|
3e47b3002b | ||
|
|
1bac6d567f | ||
|
|
92cfbf16c2 | ||
|
|
b445b26164 | ||
|
|
832c503c92 | ||
|
|
076d7fd63a | ||
|
|
3ed71070a3 | ||
|
|
08dbefedc7 | ||
|
|
4be377650e | ||
|
|
8898803b4a | ||
|
|
21f71d72f0 | ||
|
|
d79061e0c6 | ||
|
|
d951c560e4 | ||
|
|
6cf782b75c | ||
|
|
dca0f7315c | ||
|
|
0983d2dbcf | ||
|
|
d90cbec236 | ||
|
|
6e20d410bb | ||
|
|
b4f6460bff | ||
|
|
199056cf1b |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,3 +1,28 @@
|
||||
## 15.3.2 (September 19, 2016)
|
||||
|
||||
### React
|
||||
- Remove plain object warning from React.createElement & React.cloneElement. ([@spudly](https://github.com/spudly] in [#7724](https://github.com/facebook/react/pull/7724])
|
||||
|
||||
### React DOM
|
||||
- Add `playsInline` to supported HTML attributes. ([@reaperhulk](https://github.com/reaperhulk] in [#7519](https://github.com/facebook/react/pull/7519])
|
||||
- Add `as` to supported HTML attributes. ([@kevinslin](https://github.com/kevinslin] in [#7582](https://github.com/facebook/react/pull/7582])
|
||||
- Improve DOM nesting validation warning about whitespace. ([@spicyj](https://github.com/spicyj] in [#7515](https://github.com/facebook/react/pull/7515])
|
||||
- Avoid "Member not found" exception in IE10 when calling `preventDefault()` in Synthetic Events. ([@g-palmer](https://github.com/g-palmer] in [#7411](https://github.com/facebook/react/pull/7411])
|
||||
- Fix memory leak in `onSelect` implementation. ([@AgtLucas](https://github.com/AgtLucas] in [#7533](https://github.com/facebook/react/pull/7533])
|
||||
- Improve robustness of `document.documentMode` checks to handle Google Tag Manager. ([@SchleyB](https://github.com/SchleyB] in [#7594](https://github.com/facebook/react/pull/7594])
|
||||
- Add more cases to controlled inputs warning. ([@marcin-mazurek](https://github.com/marcin-mazurek] in [#7544](https://github.com/facebook/react/pull/7544])
|
||||
- Handle case of popup blockers overriding `document.createEvent`. ([@Andarist](https://github.com/Andarist] in [#7621](https://github.com/facebook/react/pull/7621])
|
||||
- Fix issue with `dangerouslySetInnerHTML` and SVG in Internet Explorer. ([@zpao](https://github.com/zpao] in [#7618](https://github.com/facebook/react/pull/7618])
|
||||
- Improve handling of Japanese IME on Internet Explorer. ([@msmania](https://github.com/msmania] in [#7107](https://github.com/facebook/react/pull/7107])
|
||||
|
||||
### React Test Renderer
|
||||
- Support error boundaries. ([@millermedeiros](https://github.com/millermedeiros] in [#7558](https://github.com/facebook/react/pull/7558], [#7569](https://github.com/facebook/react/pull/7569], [#7619](https://github.com/facebook/react/pull/7619])
|
||||
- Skip null ref warning. ([@Aweary](https://github.com/Aweary] in [#7658](https://github.com/facebook/react/pull/7658])
|
||||
|
||||
### React Perf Add-on
|
||||
- Ensure lifecycle timers are stopped on errors. ([@gaearon](https://github.com/gaearon] in [#7548](https://github.com/facebook/react/pull/7548])
|
||||
|
||||
|
||||
## 15.3.1 (August 19, 2016)
|
||||
|
||||
### React
|
||||
|
||||
@@ -31,16 +31,16 @@ You'll notice that we used an HTML-like syntax; [we call it JSX](https://faceboo
|
||||
|
||||
## Installation
|
||||
|
||||
The fastest way to get started is to serve JavaScript from a CDN. We're using [npmcdn](https://npmcdn.com/) below but React is also available on [cdnjs](https://cdnjs.com/libraries/react) and [jsdelivr](https://www.jsdelivr.com/projects/react):
|
||||
The fastest way to get started is to serve JavaScript from a CDN. We're using [unpkg](https://unpkg.com/) below but React is also available on [cdnjs](https://cdnjs.com/libraries/react) and [jsdelivr](https://www.jsdelivr.com/projects/react):
|
||||
|
||||
```html
|
||||
<!-- The core React library -->
|
||||
<script src="https://npmcdn.com/react@15.3.1/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react@15.3.2/dist/react.js"></script>
|
||||
<!-- The ReactDOM Library -->
|
||||
<script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@15.3.2/dist/react-dom.js"></script>
|
||||
```
|
||||
|
||||
We've also built a [starter kit](https://facebook.github.io/react/downloads/react-15.3.1.zip) which might be useful if this is your first time using React. It includes a webpage with an example of using React with live code.
|
||||
We've also built a [starter kit](https://facebook.github.io/react/downloads/react-15.3.2.zip) which might be useful if this is your first time using React. It includes a webpage with an example of using React with live code.
|
||||
|
||||
If you'd like to use [bower](http://bower.io), it's as easy as:
|
||||
|
||||
|
||||
5
build.sh
Normal file
5
build.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
grunt build:npm-react
|
||||
cd build/packages/react
|
||||
deps link
|
||||
npm install
|
||||
cd ../../..
|
||||
@@ -53,13 +53,13 @@ sass:
|
||||
gems:
|
||||
- jekyll-redirect-from
|
||||
- jekyll-paginate
|
||||
react_version: 15.3.0
|
||||
react_version: 15.3.1
|
||||
react_hashes:
|
||||
dev: R8v794QN9hrNjnivoQ3Mf7nMGVwFIHBkUmBanB40ZBIMttZbBEUatXNosjytvPUC
|
||||
prod: asiNTW+3f/iCKtm+05EX+4V4n6R5R1fyAY9M8Md0DLHodFResXMSBlt8ns9iJaPK
|
||||
addons_dev: iR3HmJX+5siYwRvy6ZXWWN/dNP4IuItUsfk0JJmwxaBIYtWHZhK/2N7wrAcxmpS8
|
||||
addons_prod: A/63GcxBS05SAxTWB0+wQKyQl8RVEH3nOuBuxwg/WV6yI5qpfEy4ksn90bqJdFJY
|
||||
dom_dev: PKr8yTHUBD0chzmoJ6ZYtB1nB87GTEWPmuDlDV7iARDrYGki2fmVB0ae3vf3LX0O
|
||||
dom_prod: TBEslZF7tpwiuBgt/ajgWUKvDGuCExkmEoWygscHE/OOajWS24BLAaf2/z7lj/9n
|
||||
dom_server_dev: UxEqwIE5+BLQKOqKHnPfJBOrSDo7HyocIl6sTb6taLayrVmDuhQ5VM4iauS54BbK
|
||||
dom_server_prod: hOLRkO2HGPRi0d73qKZWueHZyDD/6BID0CJax9kNUNaAvMR4atbNIcYfk2BoM8T3
|
||||
dev: gS+zau+tpUQYisQ0pOWmfNOfcczNoZQjeQ6+5jOgVqV1WBYqkIbdqpay3VuCHQjt
|
||||
prod: GjSRThJn3fjCmKim4Jou04Ax7vvKfk76xSCKUo7/V70VNIlidvZd3ZnT9rtJk0KM
|
||||
addons_dev: 37FL10I5CNyIhpG9UrOeUrUKONP5CUt3PYHxWz9Eo4kYWS7weaFzDRP7BxRfhB75
|
||||
addons_prod: hSlojvw2moZ49rKg6U9wW83sJi7QnWC6nB53jlsGy5hmltJC6ET/cRRKzMifYEg5
|
||||
dom_dev: yMyOXveaWIIfHWhBZNUrKSPQCw+BWRGucJIdsQeltkvBNDrWXKo+jKVKyx6hH/5r
|
||||
dom_prod: 3AR/0xGUlR37VpbeHbKQhvizC4T8sNTU8t5GS9JC/4odeRePZuPYl5Pyv/zTeSd8
|
||||
dom_server_dev: sPg6+OzdWmnH1aArppe66vtLc7tZ2gxh5KxXoZFHAxZoquTi4J71PHASGmv7meE1
|
||||
dom_server_prod: L4CScwloTXP7xdPmmp3KRAKqASCN8hQpjM6DsrAyCl4K8RXi8Ig+9i0X6k8AyfM9
|
||||
|
||||
@@ -19,9 +19,9 @@ Diamo un'occhiata ad un esempio davvero semplice. Creiamo un file dal nome `hell
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -19,9 +19,9 @@ UIについて、最も基本的なことは、いくつかのデータを表示
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -18,9 +18,9 @@ UI를 가지고 할 수 있는 가장 기초적인 것은 데이터를 표시하
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -18,9 +18,9 @@ Let's look at a really simple example. Create a `hello-react.html` file with the
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -18,9 +18,9 @@ next: jsx-in-depth.html
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -18,9 +18,9 @@ next: jsx-in-depth-zh-CN.html
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -18,9 +18,9 @@ next: jsx-in-depth-zh-TW.html
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -27,11 +27,11 @@ ReactDOM.render(
|
||||
```
|
||||
|
||||
Configure [babel](https://babeljs.io/) with a `.babelrc` file:
|
||||
|
||||
|
||||
```json
|
||||
{ "presets": ["react"] }
|
||||
```
|
||||
|
||||
|
||||
> Note:
|
||||
>
|
||||
> If you are using ES2015, you will want to also use the `babel-preset-es2015` package.
|
||||
@@ -67,26 +67,23 @@ new webpack.DefinePlugin({
|
||||
|
||||
Update your HTML file as below:
|
||||
|
||||
```html{8,12}
|
||||
```html{9}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React!</title>
|
||||
<script src="build/react.js"></script>
|
||||
<script src="build/react-dom.js"></script>
|
||||
<!-- No need for Babel! -->
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
<script src="build/helloworld.js"></script>
|
||||
<script src="bundle.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Using React from Bower
|
||||
|
||||
Bower is a package manager optimized for the front-end development. If multiple packages depend on a package - jQuery for example - Bower will download jQuery just once. This is known as a flat dependency graph and it helps reduce page load. For more info, visit http://bower.io/
|
||||
Bower is a package manager optimized for the front-end development. If multiple packages depend on a package - jQuery for example - Bower will download jQuery just once. This is known as a flat dependency graph and it helps reduce page load. For more info, visit [http://bower.io/](http://bower.io/).
|
||||
|
||||
If you'd like to use bower, it's as easy as:
|
||||
|
||||
@@ -102,7 +99,7 @@ bower install --save react
|
||||
<title>Hello React!</title>
|
||||
<script src="bower_components/react/react.js"></script>
|
||||
<script src="bower_components/react/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
@@ -120,4 +117,3 @@ bower install --save react
|
||||
## Using master
|
||||
|
||||
We have instructions for building from `master` [in our GitHub repository](https://github.com/facebook/react).
|
||||
|
||||
|
||||
@@ -44,7 +44,10 @@ var TodoList = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.handleAdd}>Aggiungi Elemento</button>
|
||||
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionEnterTimeout={500}
|
||||
transitionLeaveTimeout={300}>
|
||||
{items}
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
@@ -89,7 +92,10 @@ Ti accorgerai che la durata delle animazioni devono essere specificate sia nel C
|
||||
```javascript{3-5}
|
||||
render: function() {
|
||||
return (
|
||||
<ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionAppear={true}
|
||||
transitionAppearTimeout={500}>
|
||||
<h1>Dissolvenza al Montaggio Iniziale</h1>
|
||||
</ReactCSSTransitionGroup>
|
||||
);
|
||||
@@ -182,7 +188,10 @@ var ImageCarousel = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="carousel"
|
||||
transitionEnterTimeout={300}
|
||||
transitionLeaveTimeout={300}>
|
||||
<img src={this.props.imageSrc} key={this.props.imageSrc} />
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,10 @@ var TodoList = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.handleAdd}>Add Item</button>
|
||||
<ReactCSSTransitionGroup transitionName="example">
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionEnterTimeout={500}
|
||||
transitionLeaveTimeout={300}>
|
||||
{items}
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
@@ -90,7 +93,10 @@ var TodoList = React.createClass({
|
||||
```javascript{3-5}
|
||||
render: function() {
|
||||
return (
|
||||
<ReactCSSTransitionGroup transitionName="example" transitionAppear={true}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionAppear={true}
|
||||
transitionAppearTimeout={500}>
|
||||
<h1>Fading at Initial Mount</h1>
|
||||
</ReactCSSTransitionGroup>
|
||||
);
|
||||
@@ -153,7 +159,10 @@ var ImageCarousel = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<ReactCSSTransitionGroup transitionName="carousel">
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="carousel"
|
||||
transitionEnterTimeout={300}
|
||||
transitionLeaveTimeout={300}>
|
||||
<img src={this.props.imageSrc} key={this.props.imageSrc} />
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,10 @@ var TodoList = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.handleAdd}>Add Item</button>
|
||||
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionEnterTimeout={500}
|
||||
transitionLeaveTimeout={300}>
|
||||
{items}
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
@@ -90,7 +93,10 @@ var TodoList = React.createClass({
|
||||
```javascript{3-5}
|
||||
render: function() {
|
||||
return (
|
||||
<ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionAppear={true}
|
||||
transitionAppearTimeout={500}>
|
||||
<h1>Fading at Initial Mount</h1>
|
||||
</ReactCSSTransitionGroup>
|
||||
);
|
||||
@@ -183,7 +189,10 @@ var ImageCarousel = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="carousel"
|
||||
transitionEnterTimeout={300}
|
||||
transitionLeaveTimeout={300}>
|
||||
<img src={this.props.imageSrc} key={this.props.imageSrc} />
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,10 @@ var TodoList = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.handleAdd}>Add Item</button>
|
||||
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionEnterTimeout={500}
|
||||
transitionLeaveTimeout={300}>
|
||||
{items}
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
@@ -90,7 +93,10 @@ You'll notice that animation durations need to be specified in both the CSS and
|
||||
```javascript{3-5}
|
||||
render: function() {
|
||||
return (
|
||||
<ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionAppear={true}
|
||||
transitionAppearTimeout={500}>
|
||||
<h1>Fading at Initial Mount</h1>
|
||||
</ReactCSSTransitionGroup>
|
||||
);
|
||||
@@ -183,7 +189,10 @@ var ImageCarousel = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="carousel"
|
||||
transitionEnterTimeout={300}
|
||||
transitionLeaveTimeout={300}>
|
||||
<img src={this.props.imageSrc} key={this.props.imageSrc} />
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
|
||||
@@ -44,7 +44,10 @@ var TodoList = React.createClass({
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.handleAdd}>Add Item</button>
|
||||
<ReactCSSTransitionGroup transitionName="example" transitionEnterTimeout={500} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionEnterTimeout={500}
|
||||
transitionLeaveTimeout={300}>
|
||||
{items}
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
@@ -89,7 +92,10 @@ var TodoList = React.createClass({
|
||||
```javascript{3-5}
|
||||
render: function() {
|
||||
return (
|
||||
<ReactCSSTransitionGroup transitionName="example" transitionAppear={true} transitionAppearTimeout={500}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="example"
|
||||
transitionAppear={true}
|
||||
transitionAppearTimeout={500}>
|
||||
<h1>Fading at Initial Mount</h1>
|
||||
</ReactCSSTransitionGroup>
|
||||
);
|
||||
@@ -182,7 +188,10 @@ var ImageCarousel = React.createClass({
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<ReactCSSTransitionGroup transitionName="carousel" transitionEnterTimeout={300} transitionLeaveTimeout={300}>
|
||||
<ReactCSSTransitionGroup
|
||||
transitionName="carousel"
|
||||
transitionEnterTimeout={300}
|
||||
transitionLeaveTimeout={300}>
|
||||
<img src={this.props.imageSrc} key={this.props.imageSrc} />
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
|
||||
212
docs/docs/11-advanced-performance.zh-CN.md
Normal file
212
docs/docs/11-advanced-performance.zh-CN.md
Normal file
@@ -0,0 +1,212 @@
|
||||
---
|
||||
id: advanced-performance-zh-CN
|
||||
title: 提高性能
|
||||
permalink: docs/advanced-performance-zh-CN.html
|
||||
prev: shallow-compare-zh-CN.html
|
||||
next: context-zh-CN.html
|
||||
---
|
||||
|
||||
当人们考虑将React应用到自己的系统里时,都会想知道React是否可以和非React的应用一样可以快速的响应各种用户的操作。改变组件的state时,它会重新渲染组件的所有子节点,有人会怀疑这种重新渲染会带来很大的性能开销。但是React使用很多技术来最小化的减少DOM操作的开销达到更新UI的效果。
|
||||
|
||||
## 使用生产构建版本
|
||||
|
||||
如果你在开发React应用中,遇到了一些性能上的问题,你可以使用了[minified production build](/react/downloads.html)进行测试。这个开发构建版本包括了额外的一些警告信息,可以帮助你更好的调试你的应用。由于它做了很多额外的开销,所以它运行起来会相对要慢一点。
|
||||
|
||||
## 避免调整真实DOM树
|
||||
|
||||
React利用*虚拟DOM*,来描述在浏览器上显示的真实DOM树。这种并行的表示方法,可以让React避免直接去操作DOM节点,毕竟操作DOM节点的开销要远远大于直接去操作Javascript的对象。当组件的state或者props更新的时候,React会根据新生成的虚拟DOM和之前的虚拟DOM进行比较,来判断是否需要去更新真实DOM上的内容。只有在前后虚拟DOM不相等的情况下,React才会去[调整](/react/docs/reconciliation.html)真实DOM的结构。
|
||||
|
||||
在此之上,React提供了一个组件生命周期函数`shouldComponentUpdate`,它会在组件进行重渲染过程开始的时候(虚拟DOM和真实DOM进行对比)进行调用。让开发者可以短接这个过程。该函数默认会返回`true`,让React去执行更新。
|
||||
|
||||
```javascript
|
||||
shouldComponentUpdate: function(nextProps, nextState) {
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
记住一点,在React中,这个函数调用的非常频繁,所以里面的操作不能太复杂,一定要快。
|
||||
|
||||
你有几个聊天对话的消息应用程序。假设只有一个对话改变了。如果你在`ChatThread`组件中实现了`shouldComponentUpdate`函数,React可以跳过对其他线程的重渲染的步骤。
|
||||
|
||||
```javascript
|
||||
shouldComponentUpdate: function(nextProps, nextState) {
|
||||
// TODO: return whether or not current chat thread is
|
||||
// different to former one.
|
||||
}
|
||||
```
|
||||
|
||||
所以,总而言之,React可以让开发者使用`shouldComponentUpdate`函数来减少对DOM子树的调整,对于那些需要更新的组件,再进行虚拟DOMs的对比。
|
||||
|
||||
## shouldComponentUpdate 实战
|
||||
|
||||
这个一个组件的子树的结构。每一个节点表示`shouldComponentUpdate` return了什么,以及是否虚拟DOMs是相等的。最后,圆的颜色代表这个节点是否需要被重新调整。
|
||||
|
||||
<figure><img src="/react/img/docs/should-component-update.png" /></figure>
|
||||
|
||||
在上述例子中,C2节点的`shouldComponentUpdate`函数返回了`false`,所以React就不需要在这里产生新的虚拟DOM,也就不需要重新调整DOM。由于父节点C2已经在`shouldComponentUpdate`函数中返回`false`,所以它的所有子节点也就不会执行该函数。
|
||||
|
||||
对于C1和C3,`shouldComponentUpdate`函数返回了`true`,React会从上往下对子节点进行检查。对于C6节点,它返回了`true`;由于前后的虚拟DOMs不相等,所以它不得不调整真实DOM。最后在C8这个有趣的节点上。React会去对比前后虚拟DOM,由于前后是相等的,所以它不是对真实DOM进行调整。
|
||||
|
||||
请注意,React只会对C6进行DOM操作。对于C8,它通过对比虚拟DOMs的方式,避免重新渲染。对于C2的子节点以及C7,通过`shouldComponentUpdate`函数,直接忽略了虚拟DOM比较的过程,提高性能。
|
||||
|
||||
所以,我们应该怎么样来实现`shouldComponentUpdate`方法?举个例子,你有个组件仅仅只渲染一个string的文案:
|
||||
|
||||
```javascript
|
||||
React.createClass({
|
||||
propTypes: {
|
||||
value: React.PropTypes.string.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return <div>{this.props.value}</div>;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
我们可以简单的像下面一样实现`shouldComponentUpdate`
|
||||
|
||||
```javascript
|
||||
shouldComponentUpdate: function(nextProps, nextState) {
|
||||
return this.props.value !== nextProps.value;
|
||||
}
|
||||
```
|
||||
|
||||
目前为止,在props/state上处理简单的的数据结构是非常容易的。基于这种数据类型,我们可以通过mixin的方式把该函数引入到你的所有组件中去。事实上,React官方已经提供了这种方法:[PureRenderMixin](/react/docs/pure-render-mixin.html)。
|
||||
|
||||
但是,如果你的组件使用的在state或者props上使用的是可变的数据结构怎么办?组件里的prop不是以一个string的形式`'bar'`存在,而是以一种Javascript对象的形式包含了一个字符串,类似这样`{ foo: 'bar' }`:
|
||||
|
||||
```javascript
|
||||
React.createClass({
|
||||
propTypes: {
|
||||
value: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return <div>{this.props.value.foo}</div>;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
如果是这种情况,按照我们刚才的在`shouldComponentUpdate`的实现的话,是不能达到我们的预期:
|
||||
|
||||
```javascript
|
||||
// assume this.props.value is { foo: 'bar' }
|
||||
// assume nextProps.value is { foo: 'bar' },
|
||||
// but this reference is different to this.props.value
|
||||
this.props.value !== nextProps.value; // true
|
||||
```
|
||||
|
||||
因为props实际上是没有改变的,所以`shouldComponentUpdate`始终会返回`true`。为了解决这个问题,我们也有一个可选的解决方案:
|
||||
|
||||
```javascript
|
||||
shouldComponentUpdate: function(nextProps, nextState) {
|
||||
return this.props.value.foo !== nextProps.value.foo;
|
||||
}
|
||||
```
|
||||
|
||||
基本上,我们是不会利用这种深度比较去判断是否有属性改变。这样的操作十分损耗性能的,并且非常难扩展。最重要的是,如果我们没有仔细管理对象的引用关系,很可能导致对比不出结果。让我们来看看下面这个组件:
|
||||
|
||||
```javascript
|
||||
React.createClass({
|
||||
getInitialState: function() {
|
||||
return { value: { foo: 'bar' } };
|
||||
},
|
||||
|
||||
onClick: function() {
|
||||
var value = this.state.value;
|
||||
value.foo += 'bar'; // ANTI-PATTERN!
|
||||
this.setState({ value: value });
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
<InnerComponent value={this.state.value} />
|
||||
<a onClick={this.onClick}>Click me</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
子组件第一次渲染的时候,组件会收到`{ foo: 'bar' }`作为prop中的value的值。如果用户进行了点击的操作,父组件为更新state,变为`{ value: { foo: 'barbar' } }`,之后会触发子组件的重渲染的过程,子组件会收到新的prop中value的值`{ foo: 'barbar' }`。
|
||||
|
||||
问题在与,因为父子组件共同分享了一个对象的引用,当这个对象在`onClick`函数中进行修改后,子组件的prop也已经改变。所以,当重渲染的过程开始,`shouldComponentUpdate`函数就会被触发,`this.props.value.foo` 与`nextProps.value.foo`会是相等的。因为`this.props.value`和`nextProps.value`指向的是同一个对象。
|
||||
|
||||
因此,我们直接阻止了子组件进行重新渲染,整个UI也就不会把`'bar'`更新为`'barbar'`。
|
||||
|
||||
## 使用Immutable-js
|
||||
|
||||
[Immutable-js](https://github.com/facebook/immutable-js)是一个由Lee Byron编写的Javascript的数据类型库,现在已经被Facebook开源了。它通过 *结构共享* 的方式提供了一个 *持久不可变的* 的集合。让我们来看看这个到底是什么东西。
|
||||
|
||||
* *不可变*:一旦被创建,一个集合不能被其他内容所改变
|
||||
* *持久性*:新的集合可以由之前的集合创建出来,或者由一个可变的数据创建。当新的集合被创建出来,原始的集合依然有效。
|
||||
* *结构共享*:新的集合会尽可能的复用之前集合内的内容。减少重复复制来提高性能。如果新集合和原来的集合是相等的,则会直接把之前的集合返回给新集合。
|
||||
|
||||
不可变的特性让跟踪变化变得简单;每次改变总是会产生新的一个对象,所以。我们只需要判断一下它们引用是否相同即可。举个例子,下面是常规的Javascript的写法:
|
||||
|
||||
```javascript
|
||||
var x = { foo: "bar" };
|
||||
var y = x;
|
||||
y.foo = "baz";
|
||||
x === y; // true
|
||||
```
|
||||
|
||||
尽管`y`已经被更改了,但是它的引用还是和`x`是一致的。所以他们两个进行对比,始终会返回`true`。所以,这样的操作应该要用`immutable-js `来完成:
|
||||
|
||||
```javascript
|
||||
var SomeRecord = Immutable.Record({ foo: null });
|
||||
var x = new SomeRecord({ foo: 'bar' });
|
||||
var y = x.set('foo', 'baz');
|
||||
x === y; // false
|
||||
```
|
||||
|
||||
在这样的情况中,当我们改变了x里的内容,会返回给我们一个新的引用,我们可以安全地假定`x`已经改变。
|
||||
|
||||
另一种来跟踪数据变化的方法,是通过 setter 来设置标识符来做脏检查 (dirty checking)。这种方法的问题在于它强迫你使用 setter;你需要多写很多额外代码或者跟踪分析 class 中的数据。另外一种方式是,你可以在更改一个对象之前对它进行一次深复制,之后再进行深比较,来判断这次操作是否造成了数据改变:这种方案的问题在于深复制与深比较都是很昂贵的操作。
|
||||
|
||||
所以,Immutable的数据结构给你提供了一个很方便的方式去跟踪一个对象是否被修改了,我们只需要简单的实现`shouldComponentUpdate`即可。因此,如果我们的props和state模型使用了immutable-js方式,我们可以引入`PureRenderMixin`,从而提高我们的应用的性能。
|
||||
|
||||
## Immutable-js 结合 Flux
|
||||
|
||||
如果你正在使用[Flux](https://facebook.github.io/flux/),你应该在你的stores里使用immutable-js。可以来看下[full API](https://facebook.github.io/immutable-js/docs/#/)。
|
||||
|
||||
让我们看看一种使用Immutable数据结构来处理的方式。首先,我们为每一个入口定义一个`Record`去处理模型。`Record`是一个保存各个字段的一个容器。
|
||||
|
||||
```javascript
|
||||
var User = Immutable.Record({
|
||||
id: undefined,
|
||||
name: undefined,
|
||||
email: undefined
|
||||
});
|
||||
|
||||
var Message = Immutable.Record({
|
||||
timestamp: new Date(),
|
||||
sender: undefined,
|
||||
text: ''
|
||||
});
|
||||
```
|
||||
|
||||
Record 函数接受一个对象作为参数;这个对象定义了 Record 中的键值与默认值
|
||||
|
||||
*store*可以用两个list来记录users和messages
|
||||
|
||||
|
||||
```javascript
|
||||
this.users = Immutable.List();
|
||||
this.messages = Immutable.List();
|
||||
```
|
||||
|
||||
它可以很方便的实现处理*payload*数据类型。例如,当一个store收到了新的信息,我们可以直接创建一个新的record,然后把它加到我们message的list中去。
|
||||
|
||||
```javascript
|
||||
this.messages = this.messages.push(new Message({
|
||||
timestamp: payload.timestamp,
|
||||
sender: payload.sender,
|
||||
text: payload.text
|
||||
});
|
||||
```
|
||||
|
||||
注意,因为data的数据结构是不可变的,我们需要重新对`this.message`进行赋值。
|
||||
|
||||
在React方面,如果我们用了 `immutable-js`的数据结构去保存组件的state,我们就可以引入`PureRenderMixin`到所有你的组件中,做一个快速的判断是否需要重新渲染的操作。
|
||||
@@ -32,7 +32,7 @@ Nella directory principale dello starter kit, crea `helloworld.html` con il segu
|
||||
<meta charset="UTF-8" />
|
||||
<title>Ciao React!</title>
|
||||
<script src="build/react.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -32,7 +32,7 @@ React でのハッキングを始めるにあたり、一番簡単なものと
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React!</title>
|
||||
<script src="build/react.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -59,7 +59,7 @@ $ browserify -t [ babelify --presets [ react ] ] main.js -o bundle.js
|
||||
<title>Hello React!</title>
|
||||
<script src="build/react.js"></script>
|
||||
<script src="build/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -13,6 +13,11 @@ The easiest way to start hacking on React is using the following JSFiddle Hello
|
||||
* **[React JSFiddle](https://jsfiddle.net/reactjs/69z2wepo/)**
|
||||
* [React JSFiddle without JSX](https://jsfiddle.net/reactjs/5vjqabv3/)
|
||||
|
||||
## Create React App
|
||||
|
||||
**[Create React App](http://github.com/facebookincubator/create-react-app)** is a new officially supported way to create single-page React applications. It offers a modern build setup with no configuration. It requires Node 4 or higher.
|
||||
|
||||
Note that it has [some limitations](https://github.com/facebookincubator/create-react-app#limitations) and is only useful for single-page applications. If you need more flexibility, or if you want to integrate React into an existing project, consider other options below.
|
||||
|
||||
## Starter Pack
|
||||
|
||||
@@ -34,7 +39,7 @@ In the root directory of the starter kit, create a `helloworld.html` with the fo
|
||||
<title>Hello React!</title>
|
||||
<script src="build/react.js"></script>
|
||||
<script src="build/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -76,7 +76,7 @@ new webpack.DefinePlugin({
|
||||
<title>Hello React!</title>
|
||||
<script src="build/react.js"></script>
|
||||
<script src="build/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="example"></div>
|
||||
|
||||
@@ -50,8 +50,11 @@ function onClick(event) {
|
||||
console.log(eventType); // => "click"
|
||||
}, 0);
|
||||
|
||||
this.setState({clickEvent: event}); // Won't work. this.state.clickEvent will only contain null values.
|
||||
this.setState({eventType: event.type}); // You can still export event properties.
|
||||
// Won't work. this.state.clickEvent will only contain null values.
|
||||
this.setState({clickEvent: event});
|
||||
|
||||
// You can still export event properties.
|
||||
this.setState({eventType: event.type});
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ Per questo tutorial renderemo il tutto il più semplice possibile. Incluso nel p
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>React Tutorial</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://unpkg.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
@@ -228,11 +228,11 @@ Per prima cosa, aggiungiamo la libreria di terze parti **marked** alla tua appli
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>React Tutorial</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://unpkg.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
</head>
|
||||
```
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ next: thinking-in-react-ja-JP.html
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>React Tutorial</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://unpkg.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
@@ -225,11 +225,11 @@ Markdown はインラインでテキストをフォーマットする簡単な
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Hello React</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://unpkg.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
</head>
|
||||
```
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ next: thinking-in-react-ko-KR.html
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>React Tutorial</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://unpkg.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
@@ -231,11 +231,11 @@ Markdown은 텍스트를 포맷팅하는 간단한 방식입니다. 예를 들
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>React Tutorial</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://unpkg.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
</head>
|
||||
```
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ For this tutorial, we're going to make it as easy as possible. Included in the s
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>React Tutorial</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://unpkg.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
@@ -181,7 +181,7 @@ Notice how we're mixing HTML tags and components we've built. HTML components ar
|
||||
|
||||
### Using props
|
||||
|
||||
Let's create the `Comment` component, which will depend on data passed in from its parent. Data passed in from a parent component is available as a 'property' on the child component. These 'properties' are accessed through `this.props`. Using props, we will be able to read the data passed to the `Comment` from the `CommentList`, and render some markup:
|
||||
Let's create the `Comment` component, which will depend on data passed in from its parent, `CommentList`. Data passed in from a parent component is available as a 'property' on the child component. These 'properties' are accessed through `this.props`. Using props, we will be able to read the data passed to the `Comment` from the `CommentList`, and render some markup:
|
||||
|
||||
```javascript
|
||||
// tutorial4.js
|
||||
@@ -219,7 +219,7 @@ var CommentList = React.createClass({
|
||||
});
|
||||
```
|
||||
|
||||
Note that we have passed some data from the parent `CommentList` component to the child `Comment` components. For example, we passed *Pete Hunt* (via an attribute) and *This is one comment* (via an XML-like child node) to the first `Comment`. As noted above, the `Comment` component will access these 'properties' through `this.props.author`, and `this.props.children`.
|
||||
Note that we have passed some data from the parent `CommentList` component to the child `Comment` components. For example, we passed *Pete Hunt* (via the `author` attribute) and *This is one comment* (via an XML-like child node) to the first `Comment`. As noted above, the `Comment` component will access these 'properties' through `this.props.author`, and `this.props.children`.
|
||||
|
||||
### Adding Markdown
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ next: thinking-in-react-zh-CN.html
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>React Tutorial</title>
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://npmcdn.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://npmcdn.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/babel-core@5.8.38/browser.min.js"></script>
|
||||
<script src="https://unpkg.com/jquery@3.1.0/dist/jquery.min.js"></script>
|
||||
<script src="https://unpkg.com/remarkable@1.6.2/dist/remarkable.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
|
||||
@@ -22,40 +22,40 @@ If you're just starting out, make sure to use the development version.
|
||||
## Individual Downloads
|
||||
|
||||
#### React {{site.react_version}} (development)
|
||||
The uncompressed, development version of [react.js](https://npmcdn.com/react@{{site.react_version}}/dist/react.js) and [react-dom.js](https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js) with inline documentation (you need both files).
|
||||
The uncompressed, development version of [react.js](https://unpkg.com/react@{{site.react_version}}/dist/react.js) and [react-dom.js](https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js) with inline documentation (you need both files).
|
||||
|
||||
```html
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
```
|
||||
|
||||
#### React {{site.react_version}} (production)
|
||||
The compressed, production version of [react.js](https://npmcdn.com/react@{{site.react_version}}/dist/react.min.js) and [react-dom.js](https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.min.js) (you need both).
|
||||
The compressed, production version of [react.js](https://unpkg.com/react@{{site.react_version}}/dist/react.min.js) and [react-dom.js](https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.min.js) (you need both).
|
||||
|
||||
```html
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react.min.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react.min.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.min.js"></script>
|
||||
```
|
||||
|
||||
#### React with Add-Ons {{site.react_version}} (development)
|
||||
The uncompressed, development version of React with [optional add-ons](/react/docs/addons.html).
|
||||
|
||||
```html
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react-with-addons.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react-with-addons.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.js"></script>
|
||||
```
|
||||
|
||||
#### React with Add-Ons {{site.react_version}} (production)
|
||||
The compressed, production version of React with [optional add-ons](/react/docs/addons.html).
|
||||
|
||||
```html
|
||||
<script src="https://npmcdn.com/react@{{site.react_version}}/dist/react-with-addons.min.js"></script>
|
||||
<script src="https://npmcdn.com/react-dom@{{site.react_version}}/dist/react-dom.min.js"></script>
|
||||
<script src="https://unpkg.com/react@{{site.react_version}}/dist/react-with-addons.min.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@{{site.react_version}}/dist/react-dom.min.js"></script>
|
||||
```
|
||||
|
||||
> Note:
|
||||
>
|
||||
> We're using [npmcdn](https://npmcdn.com) to serve these files. This is a free service with the goal to provide a hassle-free CDN for npm package authors. React is also available on other free CDNs including [cdnjs](https://cdnjs.com/libraries/react/) and [jsDelivr](https://www.jsdelivr.com/projects/react). If you have concerns with relying on an external host, we always recommend that you download React and serve it from your own servers.
|
||||
> We're using [unpkg](https://unpkg.com) to serve these files. This is a free service with the goal to provide a hassle-free CDN for npm package authors. React is also available on other free CDNs including [cdnjs](https://cdnjs.com/libraries/react/) and [jsDelivr](https://www.jsdelivr.com/projects/react). If you have concerns with relying on an external host, we always recommend that you download React and serve it from your own servers.
|
||||
|
||||
## npm
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
2
docs/js/es5-sham.min.js
vendored
2
docs/js/es5-sham.min.js
vendored
File diff suppressed because one or more lines are too long
2
docs/js/es5-shim.min.js
vendored
2
docs/js/es5-shim.min.js
vendored
File diff suppressed because one or more lines are too long
8
docs/js/html5shiv.min.js
vendored
8
docs/js/html5shiv.min.js
vendored
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
HTML5 Shiv v3.6.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
|
||||
*/
|
||||
(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag();
|
||||
a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/\w+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x<style>article,aside,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}</style>";
|
||||
c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="<xyz></xyz>";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode||
|
||||
"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup main mark meter nav output progress section summary time video",version:"3.6.2",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f);if(g)return a.createDocumentFragment();
|
||||
for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d<h;d++)c.createElement(e[d]);return c}};l.html5=e;q(f)})(this,document);
|
||||
@@ -1,746 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
function expressionAllowed(stream, state, backUp) {
|
||||
return /^(?:operator|sof|keyword c|case|new|[\[{}\(,;:]|=>)$/.test(state.lastType) ||
|
||||
(state.lastType == "quasi" && /\{\s*$/.test(stream.string.slice(0, stream.pos - (backUp || 0))))
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("javascript", function(config, parserConfig) {
|
||||
var indentUnit = config.indentUnit;
|
||||
var statementIndent = parserConfig.statementIndent;
|
||||
var jsonldMode = parserConfig.jsonld;
|
||||
var jsonMode = parserConfig.json || jsonldMode;
|
||||
var isTS = parserConfig.typescript;
|
||||
var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;
|
||||
|
||||
// Tokenizer
|
||||
|
||||
var keywords = function(){
|
||||
function kw(type) {return {type: type, style: "keyword"};}
|
||||
var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
|
||||
var operator = kw("operator"), atom = {type: "atom", style: "atom"};
|
||||
|
||||
var jsKeywords = {
|
||||
"if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
|
||||
"return": C, "break": C, "continue": C, "new": kw("new"), "delete": C, "throw": C, "debugger": C,
|
||||
"var": kw("var"), "const": kw("var"), "let": kw("var"),
|
||||
"function": kw("function"), "catch": kw("catch"),
|
||||
"for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
|
||||
"in": operator, "typeof": operator, "instanceof": operator,
|
||||
"true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
|
||||
"this": kw("this"), "class": kw("class"), "super": kw("atom"),
|
||||
"yield": C, "export": kw("export"), "import": kw("import"), "extends": C,
|
||||
"await": C, "async": kw("async")
|
||||
};
|
||||
|
||||
// Extend the 'normal' keywords with the TypeScript language extensions
|
||||
if (isTS) {
|
||||
var type = {type: "variable", style: "variable-3"};
|
||||
var tsKeywords = {
|
||||
// object-like things
|
||||
"interface": kw("class"),
|
||||
"implements": C,
|
||||
"namespace": C,
|
||||
"module": kw("module"),
|
||||
"enum": kw("module"),
|
||||
|
||||
// scope modifiers
|
||||
"public": kw("modifier"),
|
||||
"private": kw("modifier"),
|
||||
"protected": kw("modifier"),
|
||||
"abstract": kw("modifier"),
|
||||
|
||||
// operators
|
||||
"as": operator,
|
||||
|
||||
// types
|
||||
"string": type, "number": type, "boolean": type, "any": type
|
||||
};
|
||||
|
||||
for (var attr in tsKeywords) {
|
||||
jsKeywords[attr] = tsKeywords[attr];
|
||||
}
|
||||
}
|
||||
|
||||
return jsKeywords;
|
||||
}();
|
||||
|
||||
var isOperatorChar = /[+\-*&%=<>!?|~^]/;
|
||||
var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;
|
||||
|
||||
function readRegexp(stream) {
|
||||
var escaped = false, next, inSet = false;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped) {
|
||||
if (next == "/" && !inSet) return;
|
||||
if (next == "[") inSet = true;
|
||||
else if (inSet && next == "]") inSet = false;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
}
|
||||
|
||||
// Used as scratch variables to communicate multiple values without
|
||||
// consing up tons of objects.
|
||||
var type, content;
|
||||
function ret(tp, style, cont) {
|
||||
type = tp; content = cont;
|
||||
return style;
|
||||
}
|
||||
function tokenBase(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == '"' || ch == "'") {
|
||||
state.tokenize = tokenString(ch);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
|
||||
return ret("number", "number");
|
||||
} else if (ch == "." && stream.match("..")) {
|
||||
return ret("spread", "meta");
|
||||
} else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
|
||||
return ret(ch);
|
||||
} else if (ch == "=" && stream.eat(">")) {
|
||||
return ret("=>", "operator");
|
||||
} else if (ch == "0" && stream.eat(/x/i)) {
|
||||
stream.eatWhile(/[\da-f]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/o/i)) {
|
||||
stream.eatWhile(/[0-7]/i);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "0" && stream.eat(/b/i)) {
|
||||
stream.eatWhile(/[01]/i);
|
||||
return ret("number", "number");
|
||||
} else if (/\d/.test(ch)) {
|
||||
stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
|
||||
return ret("number", "number");
|
||||
} else if (ch == "/") {
|
||||
if (stream.eat("*")) {
|
||||
state.tokenize = tokenComment;
|
||||
return tokenComment(stream, state);
|
||||
} else if (stream.eat("/")) {
|
||||
stream.skipToEnd();
|
||||
return ret("comment", "comment");
|
||||
} else if (expressionAllowed(stream, state, 1)) {
|
||||
readRegexp(stream);
|
||||
stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
|
||||
return ret("regexp", "string-2");
|
||||
} else {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
}
|
||||
} else if (ch == "`") {
|
||||
state.tokenize = tokenQuasi;
|
||||
return tokenQuasi(stream, state);
|
||||
} else if (ch == "#") {
|
||||
stream.skipToEnd();
|
||||
return ret("error", "error");
|
||||
} else if (isOperatorChar.test(ch)) {
|
||||
stream.eatWhile(isOperatorChar);
|
||||
return ret("operator", "operator", stream.current());
|
||||
} else if (wordRE.test(ch)) {
|
||||
stream.eatWhile(wordRE);
|
||||
var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
|
||||
return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
|
||||
ret("variable", "variable", word);
|
||||
}
|
||||
}
|
||||
|
||||
function tokenString(quote) {
|
||||
return function(stream, state) {
|
||||
var escaped = false, next;
|
||||
if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)){
|
||||
state.tokenize = tokenBase;
|
||||
return ret("jsonld-keyword", "meta");
|
||||
}
|
||||
while ((next = stream.next()) != null) {
|
||||
if (next == quote && !escaped) break;
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
if (!escaped) state.tokenize = tokenBase;
|
||||
return ret("string", "string");
|
||||
};
|
||||
}
|
||||
|
||||
function tokenComment(stream, state) {
|
||||
var maybeEnd = false, ch;
|
||||
while (ch = stream.next()) {
|
||||
if (ch == "/" && maybeEnd) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
maybeEnd = (ch == "*");
|
||||
}
|
||||
return ret("comment", "comment");
|
||||
}
|
||||
|
||||
function tokenQuasi(stream, state) {
|
||||
var escaped = false, next;
|
||||
while ((next = stream.next()) != null) {
|
||||
if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
|
||||
state.tokenize = tokenBase;
|
||||
break;
|
||||
}
|
||||
escaped = !escaped && next == "\\";
|
||||
}
|
||||
return ret("quasi", "string-2", stream.current());
|
||||
}
|
||||
|
||||
var brackets = "([{}])";
|
||||
// This is a crude lookahead trick to try and notice that we're
|
||||
// parsing the argument patterns for a fat-arrow function before we
|
||||
// actually hit the arrow token. It only works if the arrow is on
|
||||
// the same line as the arguments and there's no strange noise
|
||||
// (comments) in between. Fallback is to only notice when we hit the
|
||||
// arrow, and not declare the arguments as locals for the arrow
|
||||
// body.
|
||||
function findFatArrow(stream, state) {
|
||||
if (state.fatArrowAt) state.fatArrowAt = null;
|
||||
var arrow = stream.string.indexOf("=>", stream.start);
|
||||
if (arrow < 0) return;
|
||||
|
||||
var depth = 0, sawSomething = false;
|
||||
for (var pos = arrow - 1; pos >= 0; --pos) {
|
||||
var ch = stream.string.charAt(pos);
|
||||
var bracket = brackets.indexOf(ch);
|
||||
if (bracket >= 0 && bracket < 3) {
|
||||
if (!depth) { ++pos; break; }
|
||||
if (--depth == 0) break;
|
||||
} else if (bracket >= 3 && bracket < 6) {
|
||||
++depth;
|
||||
} else if (wordRE.test(ch)) {
|
||||
sawSomething = true;
|
||||
} else if (/["'\/]/.test(ch)) {
|
||||
return;
|
||||
} else if (sawSomething && !depth) {
|
||||
++pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sawSomething && !depth) state.fatArrowAt = pos;
|
||||
}
|
||||
|
||||
// Parser
|
||||
|
||||
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true};
|
||||
|
||||
function JSLexical(indented, column, type, align, prev, info) {
|
||||
this.indented = indented;
|
||||
this.column = column;
|
||||
this.type = type;
|
||||
this.prev = prev;
|
||||
this.info = info;
|
||||
if (align != null) this.align = align;
|
||||
}
|
||||
|
||||
function inScope(state, varname) {
|
||||
for (var v = state.localVars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
for (var cx = state.context; cx; cx = cx.prev) {
|
||||
for (var v = cx.vars; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
}
|
||||
}
|
||||
|
||||
function parseJS(state, style, type, content, stream) {
|
||||
var cc = state.cc;
|
||||
// Communicate our context to the combinators.
|
||||
// (Less wasteful than consing up a hundred closures on every call.)
|
||||
cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;
|
||||
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = true;
|
||||
|
||||
while(true) {
|
||||
var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
|
||||
if (combinator(type, content)) {
|
||||
while(cc.length && cc[cc.length - 1].lex)
|
||||
cc.pop()();
|
||||
if (cx.marked) return cx.marked;
|
||||
if (type == "variable" && inScope(state, content)) return "variable-2";
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combinator utils
|
||||
|
||||
var cx = {state: null, column: null, marked: null, cc: null};
|
||||
function pass() {
|
||||
for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
|
||||
}
|
||||
function cont() {
|
||||
pass.apply(null, arguments);
|
||||
return true;
|
||||
}
|
||||
function register(varname) {
|
||||
function inList(list) {
|
||||
for (var v = list; v; v = v.next)
|
||||
if (v.name == varname) return true;
|
||||
return false;
|
||||
}
|
||||
var state = cx.state;
|
||||
cx.marked = "def";
|
||||
if (state.context) {
|
||||
if (inList(state.localVars)) return;
|
||||
state.localVars = {name: varname, next: state.localVars};
|
||||
} else {
|
||||
if (inList(state.globalVars)) return;
|
||||
if (parserConfig.globalVars)
|
||||
state.globalVars = {name: varname, next: state.globalVars};
|
||||
}
|
||||
}
|
||||
|
||||
// Combinators
|
||||
|
||||
var defaultVars = {name: "this", next: {name: "arguments"}};
|
||||
function pushcontext() {
|
||||
cx.state.context = {prev: cx.state.context, vars: cx.state.localVars};
|
||||
cx.state.localVars = defaultVars;
|
||||
}
|
||||
function popcontext() {
|
||||
cx.state.localVars = cx.state.context.vars;
|
||||
cx.state.context = cx.state.context.prev;
|
||||
}
|
||||
function pushlex(type, info) {
|
||||
var result = function() {
|
||||
var state = cx.state, indent = state.indented;
|
||||
if (state.lexical.type == "stat") indent = state.lexical.indented;
|
||||
else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
|
||||
indent = outer.indented;
|
||||
state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
|
||||
};
|
||||
result.lex = true;
|
||||
return result;
|
||||
}
|
||||
function poplex() {
|
||||
var state = cx.state;
|
||||
if (state.lexical.prev) {
|
||||
if (state.lexical.type == ")")
|
||||
state.indented = state.lexical.indented;
|
||||
state.lexical = state.lexical.prev;
|
||||
}
|
||||
}
|
||||
poplex.lex = true;
|
||||
|
||||
function expect(wanted) {
|
||||
function exp(type) {
|
||||
if (type == wanted) return cont();
|
||||
else if (wanted == ";") return pass();
|
||||
else return cont(exp);
|
||||
};
|
||||
return exp;
|
||||
}
|
||||
|
||||
function statement(type, value) {
|
||||
if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
|
||||
if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
|
||||
if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
|
||||
if (type == "{") return cont(pushlex("}"), block, poplex);
|
||||
if (type == ";") return cont();
|
||||
if (type == "if") {
|
||||
if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
|
||||
cx.state.cc.pop()();
|
||||
return cont(pushlex("form"), expression, statement, poplex, maybeelse);
|
||||
}
|
||||
if (type == "function") return cont(functiondef);
|
||||
if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
|
||||
if (type == "variable") return cont(pushlex("stat"), maybelabel);
|
||||
if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
|
||||
block, poplex, poplex);
|
||||
if (type == "case") return cont(expression, expect(":"));
|
||||
if (type == "default") return cont(expect(":"));
|
||||
if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
|
||||
statement, poplex, popcontext);
|
||||
if (type == "class") return cont(pushlex("form"), className, poplex);
|
||||
if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
|
||||
if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
|
||||
if (type == "module") return cont(pushlex("form"), pattern, pushlex("}"), expect("{"), block, poplex, poplex)
|
||||
if (type == "async") return cont(statement)
|
||||
return pass(pushlex("stat"), expression, expect(";"), poplex);
|
||||
}
|
||||
function expression(type) {
|
||||
return expressionInner(type, false);
|
||||
}
|
||||
function expressionNoComma(type) {
|
||||
return expressionInner(type, true);
|
||||
}
|
||||
function expressionInner(type, noComma) {
|
||||
if (cx.state.fatArrowAt == cx.stream.start) {
|
||||
var body = noComma ? arrowBodyNoComma : arrowBody;
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
|
||||
else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
|
||||
}
|
||||
|
||||
var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
|
||||
if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
|
||||
if (type == "function") return cont(functiondef, maybeop);
|
||||
if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
|
||||
if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
|
||||
if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
|
||||
if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
|
||||
if (type == "{") return contCommasep(objprop, "}", null, maybeop);
|
||||
if (type == "quasi") return pass(quasi, maybeop);
|
||||
if (type == "new") return cont(maybeTarget(noComma));
|
||||
return cont();
|
||||
}
|
||||
function maybeexpression(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expression);
|
||||
}
|
||||
function maybeexpressionNoComma(type) {
|
||||
if (type.match(/[;\}\)\],]/)) return pass();
|
||||
return pass(expressionNoComma);
|
||||
}
|
||||
|
||||
function maybeoperatorComma(type, value) {
|
||||
if (type == ",") return cont(expression);
|
||||
return maybeoperatorNoComma(type, value, false);
|
||||
}
|
||||
function maybeoperatorNoComma(type, value, noComma) {
|
||||
var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
|
||||
var expr = noComma == false ? expression : expressionNoComma;
|
||||
if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
|
||||
if (type == "operator") {
|
||||
if (/\+\+|--/.test(value)) return cont(me);
|
||||
if (value == "?") return cont(expression, expect(":"), expr);
|
||||
return cont(expr);
|
||||
}
|
||||
if (type == "quasi") { return pass(quasi, me); }
|
||||
if (type == ";") return;
|
||||
if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
|
||||
if (type == ".") return cont(property, me);
|
||||
if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
|
||||
}
|
||||
function quasi(type, value) {
|
||||
if (type != "quasi") return pass();
|
||||
if (value.slice(value.length - 2) != "${") return cont(quasi);
|
||||
return cont(expression, continueQuasi);
|
||||
}
|
||||
function continueQuasi(type) {
|
||||
if (type == "}") {
|
||||
cx.marked = "string-2";
|
||||
cx.state.tokenize = tokenQuasi;
|
||||
return cont(quasi);
|
||||
}
|
||||
}
|
||||
function arrowBody(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expression);
|
||||
}
|
||||
function arrowBodyNoComma(type) {
|
||||
findFatArrow(cx.stream, cx.state);
|
||||
return pass(type == "{" ? statement : expressionNoComma);
|
||||
}
|
||||
function maybeTarget(noComma) {
|
||||
return function(type) {
|
||||
if (type == ".") return cont(noComma ? targetNoComma : target);
|
||||
else return pass(noComma ? expressionNoComma : expression);
|
||||
};
|
||||
}
|
||||
function target(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorComma); }
|
||||
}
|
||||
function targetNoComma(_, value) {
|
||||
if (value == "target") { cx.marked = "keyword"; return cont(maybeoperatorNoComma); }
|
||||
}
|
||||
function maybelabel(type) {
|
||||
if (type == ":") return cont(poplex, statement);
|
||||
return pass(maybeoperatorComma, expect(";"), poplex);
|
||||
}
|
||||
function property(type) {
|
||||
if (type == "variable") {cx.marked = "property"; return cont();}
|
||||
}
|
||||
function objprop(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(getterSetter);
|
||||
return cont(afterprop);
|
||||
} else if (type == "number" || type == "string") {
|
||||
cx.marked = jsonldMode ? "property" : (cx.style + " property");
|
||||
return cont(afterprop);
|
||||
} else if (type == "jsonld-keyword") {
|
||||
return cont(afterprop);
|
||||
} else if (type == "modifier") {
|
||||
return cont(objprop)
|
||||
} else if (type == "[") {
|
||||
return cont(expression, expect("]"), afterprop);
|
||||
} else if (type == "spread") {
|
||||
return cont(expression);
|
||||
}
|
||||
}
|
||||
function getterSetter(type) {
|
||||
if (type != "variable") return pass(afterprop);
|
||||
cx.marked = "property";
|
||||
return cont(functiondef);
|
||||
}
|
||||
function afterprop(type) {
|
||||
if (type == ":") return cont(expressionNoComma);
|
||||
if (type == "(") return pass(functiondef);
|
||||
}
|
||||
function commasep(what, end) {
|
||||
function proceed(type, value) {
|
||||
if (type == ",") {
|
||||
var lex = cx.state.lexical;
|
||||
if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
|
||||
return cont(what, proceed);
|
||||
}
|
||||
if (type == end || value == end) return cont();
|
||||
return cont(expect(end));
|
||||
}
|
||||
return function(type, value) {
|
||||
if (type == end || value == end) return cont();
|
||||
return pass(what, proceed);
|
||||
};
|
||||
}
|
||||
function contCommasep(what, end, info) {
|
||||
for (var i = 3; i < arguments.length; i++)
|
||||
cx.cc.push(arguments[i]);
|
||||
return cont(pushlex(end, info), commasep(what, end), poplex);
|
||||
}
|
||||
function block(type) {
|
||||
if (type == "}") return cont();
|
||||
return pass(statement, block);
|
||||
}
|
||||
function maybetype(type) {
|
||||
if (isTS && type == ":") return cont(typeexpr);
|
||||
}
|
||||
function maybedefault(_, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
function typeexpr(type) {
|
||||
if (type == "variable") {cx.marked = "variable-3"; return cont(afterType);}
|
||||
}
|
||||
function afterType(type, value) {
|
||||
if (value == "<") return cont(commasep(typeexpr, ">"), afterType)
|
||||
if (type == "[") return cont(expect("]"), afterType)
|
||||
}
|
||||
function vardef() {
|
||||
return pass(pattern, maybetype, maybeAssign, vardefCont);
|
||||
}
|
||||
function pattern(type, value) {
|
||||
if (type == "modifier") return cont(pattern)
|
||||
if (type == "variable") { register(value); return cont(); }
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "[") return contCommasep(pattern, "]");
|
||||
if (type == "{") return contCommasep(proppattern, "}");
|
||||
}
|
||||
function proppattern(type, value) {
|
||||
if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
|
||||
register(value);
|
||||
return cont(maybeAssign);
|
||||
}
|
||||
if (type == "variable") cx.marked = "property";
|
||||
if (type == "spread") return cont(pattern);
|
||||
if (type == "}") return pass();
|
||||
return cont(expect(":"), pattern, maybeAssign);
|
||||
}
|
||||
function maybeAssign(_type, value) {
|
||||
if (value == "=") return cont(expressionNoComma);
|
||||
}
|
||||
function vardefCont(type) {
|
||||
if (type == ",") return cont(vardef);
|
||||
}
|
||||
function maybeelse(type, value) {
|
||||
if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
|
||||
}
|
||||
function forspec(type) {
|
||||
if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
|
||||
}
|
||||
function forspec1(type) {
|
||||
if (type == "var") return cont(vardef, expect(";"), forspec2);
|
||||
if (type == ";") return cont(forspec2);
|
||||
if (type == "variable") return cont(formaybeinof);
|
||||
return pass(expression, expect(";"), forspec2);
|
||||
}
|
||||
function formaybeinof(_type, value) {
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return cont(maybeoperatorComma, forspec2);
|
||||
}
|
||||
function forspec2(type, value) {
|
||||
if (type == ";") return cont(forspec3);
|
||||
if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
|
||||
return pass(expression, expect(";"), forspec3);
|
||||
}
|
||||
function forspec3(type) {
|
||||
if (type != ")") cont(expression);
|
||||
}
|
||||
function functiondef(type, value) {
|
||||
if (value == "*") {cx.marked = "keyword"; return cont(functiondef);}
|
||||
if (type == "variable") {register(value); return cont(functiondef);}
|
||||
if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, maybetype, statement, popcontext);
|
||||
}
|
||||
function funarg(type) {
|
||||
if (type == "spread") return cont(funarg);
|
||||
return pass(pattern, maybetype, maybedefault);
|
||||
}
|
||||
function className(type, value) {
|
||||
if (type == "variable") {register(value); return cont(classNameAfter);}
|
||||
}
|
||||
function classNameAfter(type, value) {
|
||||
if (value == "extends") return cont(expression, classNameAfter);
|
||||
if (type == "{") return cont(pushlex("}"), classBody, poplex);
|
||||
}
|
||||
function classBody(type, value) {
|
||||
if (type == "variable" || cx.style == "keyword") {
|
||||
if (value == "static") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
cx.marked = "property";
|
||||
if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
|
||||
return cont(functiondef, classBody);
|
||||
}
|
||||
if (value == "*") {
|
||||
cx.marked = "keyword";
|
||||
return cont(classBody);
|
||||
}
|
||||
if (type == ";") return cont(classBody);
|
||||
if (type == "}") return cont();
|
||||
}
|
||||
function classGetterSetter(type) {
|
||||
if (type != "variable") return pass();
|
||||
cx.marked = "property";
|
||||
return cont();
|
||||
}
|
||||
function afterExport(_type, value) {
|
||||
if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
|
||||
if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
|
||||
return pass(statement);
|
||||
}
|
||||
function afterImport(type) {
|
||||
if (type == "string") return cont();
|
||||
return pass(importSpec, maybeFrom);
|
||||
}
|
||||
function importSpec(type, value) {
|
||||
if (type == "{") return contCommasep(importSpec, "}");
|
||||
if (type == "variable") register(value);
|
||||
if (value == "*") cx.marked = "keyword";
|
||||
return cont(maybeAs);
|
||||
}
|
||||
function maybeAs(_type, value) {
|
||||
if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
|
||||
}
|
||||
function maybeFrom(_type, value) {
|
||||
if (value == "from") { cx.marked = "keyword"; return cont(expression); }
|
||||
}
|
||||
function arrayLiteral(type) {
|
||||
if (type == "]") return cont();
|
||||
return pass(expressionNoComma, maybeArrayComprehension);
|
||||
}
|
||||
function maybeArrayComprehension(type) {
|
||||
if (type == "for") return pass(comprehension, expect("]"));
|
||||
if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
|
||||
return pass(commasep(expressionNoComma, "]"));
|
||||
}
|
||||
function comprehension(type) {
|
||||
if (type == "for") return cont(forspec, comprehension);
|
||||
if (type == "if") return cont(expression, comprehension);
|
||||
}
|
||||
|
||||
function isContinuedStatement(state, textAfter) {
|
||||
return state.lastType == "operator" || state.lastType == "," ||
|
||||
isOperatorChar.test(textAfter.charAt(0)) ||
|
||||
/[,.]/.test(textAfter.charAt(0));
|
||||
}
|
||||
|
||||
// Interface
|
||||
|
||||
return {
|
||||
startState: function(basecolumn) {
|
||||
var state = {
|
||||
tokenize: tokenBase,
|
||||
lastType: "sof",
|
||||
cc: [],
|
||||
lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
|
||||
localVars: parserConfig.localVars,
|
||||
context: parserConfig.localVars && {vars: parserConfig.localVars},
|
||||
indented: basecolumn || 0
|
||||
};
|
||||
if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
|
||||
state.globalVars = parserConfig.globalVars;
|
||||
return state;
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (stream.sol()) {
|
||||
if (!state.lexical.hasOwnProperty("align"))
|
||||
state.lexical.align = false;
|
||||
state.indented = stream.indentation();
|
||||
findFatArrow(stream, state);
|
||||
}
|
||||
if (state.tokenize != tokenComment && stream.eatSpace()) return null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if (type == "comment") return style;
|
||||
state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
|
||||
return parseJS(state, style, type, content, stream);
|
||||
},
|
||||
|
||||
indent: function(state, textAfter) {
|
||||
if (state.tokenize == tokenComment) return CodeMirror.Pass;
|
||||
if (state.tokenize != tokenBase) return 0;
|
||||
var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
|
||||
// Kludge to prevent 'maybelse' from blocking lexical scope pops
|
||||
if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
|
||||
var c = state.cc[i];
|
||||
if (c == poplex) lexical = lexical.prev;
|
||||
else if (c != maybeelse) break;
|
||||
}
|
||||
if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
|
||||
if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
|
||||
lexical = lexical.prev;
|
||||
var type = lexical.type, closing = firstChar == type;
|
||||
|
||||
if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
|
||||
else if (type == "form" && firstChar == "{") return lexical.indented;
|
||||
else if (type == "form") return lexical.indented + indentUnit;
|
||||
else if (type == "stat")
|
||||
return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
|
||||
else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
|
||||
return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
|
||||
else if (lexical.align) return lexical.column + (closing ? 0 : 1);
|
||||
else return lexical.indented + (closing ? 0 : indentUnit);
|
||||
},
|
||||
|
||||
electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
|
||||
blockCommentStart: jsonMode ? null : "/*",
|
||||
blockCommentEnd: jsonMode ? null : "*/",
|
||||
lineComment: jsonMode ? null : "//",
|
||||
fold: "brace",
|
||||
closeBrackets: "()[]{}''\"\"``",
|
||||
|
||||
helperType: jsonMode ? "json" : "javascript",
|
||||
jsonldMode: jsonldMode,
|
||||
jsonMode: jsonMode,
|
||||
|
||||
expressionAllowed: expressionAllowed,
|
||||
skipExpression: function(state) {
|
||||
var top = state.cc[state.cc.length - 1]
|
||||
if (top == expression || top == expressionNoComma) state.cc.pop()
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);
|
||||
|
||||
CodeMirror.defineMIME("text/javascript", "javascript");
|
||||
CodeMirror.defineMIME("text/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/x-javascript", "javascript");
|
||||
CodeMirror.defineMIME("application/ecmascript", "javascript");
|
||||
CodeMirror.defineMIME("application/json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/x-json", {name: "javascript", json: true});
|
||||
CodeMirror.defineMIME("application/ld+json", {name: "javascript", jsonld: true});
|
||||
CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
|
||||
CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });
|
||||
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
(function() {
|
||||
var tag = document.querySelector(
|
||||
'script[type="application/javascript;version=1.7"]'
|
||||
);
|
||||
if (!tag || tag.textContent.indexOf('window.onload=function(){') !== -1) {
|
||||
alert('Bad JSFiddle configuration, please fork the original React JSFiddle');
|
||||
}
|
||||
tag.setAttribute('type', 'text/babel');
|
||||
tag.textContent = tag.textContent.replace(/^\/\/<!\[CDATA\[/, '');
|
||||
})();
|
||||
147
docs/js/jsx.js
147
docs/js/jsx.js
@@ -1,147 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../javascript/javascript"))
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror", "../xml/xml", "../javascript/javascript"], mod)
|
||||
else // Plain browser env
|
||||
mod(CodeMirror)
|
||||
})(function(CodeMirror) {
|
||||
"use strict"
|
||||
|
||||
// Depth means the amount of open braces in JS context, in XML
|
||||
// context 0 means not in tag, 1 means in tag, and 2 means in tag
|
||||
// and js block comment.
|
||||
function Context(state, mode, depth, prev) {
|
||||
this.state = state; this.mode = mode; this.depth = depth; this.prev = prev
|
||||
}
|
||||
|
||||
function copyContext(context) {
|
||||
return new Context(CodeMirror.copyState(context.mode, context.state),
|
||||
context.mode,
|
||||
context.depth,
|
||||
context.prev && copyContext(context.prev))
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("jsx", function(config, modeConfig) {
|
||||
var xmlMode = CodeMirror.getMode(config, {name: "xml", allowMissing: true, multilineTagIndentPastTag: false})
|
||||
var jsMode = CodeMirror.getMode(config, modeConfig && modeConfig.base || "javascript")
|
||||
|
||||
function flatXMLIndent(state) {
|
||||
var tagName = state.tagName
|
||||
state.tagName = null
|
||||
var result = xmlMode.indent(state, "")
|
||||
state.tagName = tagName
|
||||
return result
|
||||
}
|
||||
|
||||
function token(stream, state) {
|
||||
if (state.context.mode == xmlMode)
|
||||
return xmlToken(stream, state, state.context)
|
||||
else
|
||||
return jsToken(stream, state, state.context)
|
||||
}
|
||||
|
||||
function xmlToken(stream, state, cx) {
|
||||
if (cx.depth == 2) { // Inside a JS /* */ comment
|
||||
if (stream.match(/^.*?\*\//)) cx.depth = 1
|
||||
else stream.skipToEnd()
|
||||
return "comment"
|
||||
}
|
||||
|
||||
if (stream.peek() == "{") {
|
||||
xmlMode.skipAttribute(cx.state)
|
||||
|
||||
var indent = flatXMLIndent(cx.state), xmlContext = cx.state.context
|
||||
// If JS starts on same line as tag
|
||||
if (xmlContext && stream.match(/^[^>]*>\s*$/, false)) {
|
||||
while (xmlContext.prev && !xmlContext.startOfLine)
|
||||
xmlContext = xmlContext.prev
|
||||
// If tag starts the line, use XML indentation level
|
||||
if (xmlContext.startOfLine) indent -= config.indentUnit
|
||||
// Else use JS indentation level
|
||||
else if (cx.prev.state.lexical) indent = cx.prev.state.lexical.indented
|
||||
// Else if inside of tag
|
||||
} else if (cx.depth == 1) {
|
||||
indent += config.indentUnit
|
||||
}
|
||||
|
||||
state.context = new Context(CodeMirror.startState(jsMode, indent),
|
||||
jsMode, 0, state.context)
|
||||
return null
|
||||
}
|
||||
|
||||
if (cx.depth == 1) { // Inside of tag
|
||||
if (stream.peek() == "<") { // Tag inside of tag
|
||||
xmlMode.skipAttribute(cx.state)
|
||||
state.context = new Context(CodeMirror.startState(xmlMode, flatXMLIndent(cx.state)),
|
||||
xmlMode, 0, state.context)
|
||||
return null
|
||||
} else if (stream.match("//")) {
|
||||
stream.skipToEnd()
|
||||
return "comment"
|
||||
} else if (stream.match("/*")) {
|
||||
cx.depth = 2
|
||||
return token(stream, state)
|
||||
}
|
||||
}
|
||||
|
||||
var style = xmlMode.token(stream, cx.state), cur = stream.current(), stop
|
||||
if (/\btag\b/.test(style)) {
|
||||
if (/>$/.test(cur)) {
|
||||
if (cx.state.context) cx.depth = 0
|
||||
else state.context = state.context.prev
|
||||
} else if (/^</.test(cur)) {
|
||||
cx.depth = 1
|
||||
}
|
||||
} else if (!style && (stop = cur.indexOf("{")) > -1) {
|
||||
stream.backUp(cur.length - stop)
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
function jsToken(stream, state, cx) {
|
||||
if (stream.peek() == "<" && jsMode.expressionAllowed(stream, cx.state)) {
|
||||
jsMode.skipExpression(cx.state)
|
||||
state.context = new Context(CodeMirror.startState(xmlMode, jsMode.indent(cx.state, "")),
|
||||
xmlMode, 0, state.context)
|
||||
return null
|
||||
}
|
||||
|
||||
var style = jsMode.token(stream, cx.state)
|
||||
if (!style && cx.depth != null) {
|
||||
var cur = stream.current()
|
||||
if (cur == "{") {
|
||||
cx.depth++
|
||||
} else if (cur == "}") {
|
||||
if (--cx.depth == 0) state.context = state.context.prev
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function() {
|
||||
return {context: new Context(CodeMirror.startState(jsMode), jsMode)}
|
||||
},
|
||||
|
||||
copyState: function(state) {
|
||||
return {context: copyContext(state.context)}
|
||||
},
|
||||
|
||||
token: token,
|
||||
|
||||
indent: function(state, textAfter, fullLine) {
|
||||
return state.context.mode.indent(state.context.state, textAfter, fullLine)
|
||||
},
|
||||
|
||||
innerMode: function(state) {
|
||||
return state.context
|
||||
}
|
||||
}
|
||||
}, "xml", "javascript")
|
||||
|
||||
CodeMirror.defineMIME("text/jsx", "jsx")
|
||||
});
|
||||
42
docs/js/react-dom.js
vendored
42
docs/js/react-dom.js
vendored
@@ -1,42 +0,0 @@
|
||||
/**
|
||||
* ReactDOM v15.3.0
|
||||
*
|
||||
* Copyright 2013-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
*/
|
||||
// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
|
||||
;(function(f) {
|
||||
// CommonJS
|
||||
if (typeof exports === "object" && typeof module !== "undefined") {
|
||||
module.exports = f(require('react'));
|
||||
|
||||
// RequireJS
|
||||
} else if (typeof define === "function" && define.amd) {
|
||||
define(['react'], f);
|
||||
|
||||
// <script>
|
||||
} else {
|
||||
var g;
|
||||
if (typeof window !== "undefined") {
|
||||
g = window;
|
||||
} else if (typeof global !== "undefined") {
|
||||
g = global;
|
||||
} else if (typeof self !== "undefined") {
|
||||
g = self;
|
||||
} else {
|
||||
// works providing we're not in "use strict";
|
||||
// needed for Java 8 Nashorn
|
||||
// see https://github.com/facebook/react/issues/3037
|
||||
g = this;
|
||||
}
|
||||
g.ReactDOM = f(g.React);
|
||||
}
|
||||
|
||||
})(function(React) {
|
||||
return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
||||
});
|
||||
20640
docs/js/react.js
vendored
20640
docs/js/react.js
vendored
File diff suppressed because it is too large
Load Diff
4
docs/js/remarkable.min.js
vendored
4
docs/js/remarkable.min.js
vendored
File diff suppressed because one or more lines are too long
394
docs/js/xml.js
394
docs/js/xml.js
@@ -1,394 +0,0 @@
|
||||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||||
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||||
|
||||
(function(mod) {
|
||||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
||||
mod(require("../../lib/codemirror"));
|
||||
else if (typeof define == "function" && define.amd) // AMD
|
||||
define(["../../lib/codemirror"], mod);
|
||||
else // Plain browser env
|
||||
mod(CodeMirror);
|
||||
})(function(CodeMirror) {
|
||||
"use strict";
|
||||
|
||||
var htmlConfig = {
|
||||
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
|
||||
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
|
||||
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
|
||||
'track': true, 'wbr': true, 'menuitem': true},
|
||||
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
|
||||
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
|
||||
'th': true, 'tr': true},
|
||||
contextGrabbers: {
|
||||
'dd': {'dd': true, 'dt': true},
|
||||
'dt': {'dd': true, 'dt': true},
|
||||
'li': {'li': true},
|
||||
'option': {'option': true, 'optgroup': true},
|
||||
'optgroup': {'optgroup': true},
|
||||
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
|
||||
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
|
||||
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
|
||||
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
|
||||
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
|
||||
'rp': {'rp': true, 'rt': true},
|
||||
'rt': {'rp': true, 'rt': true},
|
||||
'tbody': {'tbody': true, 'tfoot': true},
|
||||
'td': {'td': true, 'th': true},
|
||||
'tfoot': {'tbody': true},
|
||||
'th': {'td': true, 'th': true},
|
||||
'thead': {'tbody': true, 'tfoot': true},
|
||||
'tr': {'tr': true}
|
||||
},
|
||||
doNotIndent: {"pre": true},
|
||||
allowUnquoted: true,
|
||||
allowMissing: true,
|
||||
caseFold: true
|
||||
}
|
||||
|
||||
var xmlConfig = {
|
||||
autoSelfClosers: {},
|
||||
implicitlyClosed: {},
|
||||
contextGrabbers: {},
|
||||
doNotIndent: {},
|
||||
allowUnquoted: false,
|
||||
allowMissing: false,
|
||||
caseFold: false
|
||||
}
|
||||
|
||||
CodeMirror.defineMode("xml", function(editorConf, config_) {
|
||||
var indentUnit = editorConf.indentUnit
|
||||
var config = {}
|
||||
var defaults = config_.htmlMode ? htmlConfig : xmlConfig
|
||||
for (var prop in defaults) config[prop] = defaults[prop]
|
||||
for (var prop in config_) config[prop] = config_[prop]
|
||||
|
||||
// Return variables for tokenizers
|
||||
var type, setStyle;
|
||||
|
||||
function inText(stream, state) {
|
||||
function chain(parser) {
|
||||
state.tokenize = parser;
|
||||
return parser(stream, state);
|
||||
}
|
||||
|
||||
var ch = stream.next();
|
||||
if (ch == "<") {
|
||||
if (stream.eat("!")) {
|
||||
if (stream.eat("[")) {
|
||||
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
|
||||
else return null;
|
||||
} else if (stream.match("--")) {
|
||||
return chain(inBlock("comment", "-->"));
|
||||
} else if (stream.match("DOCTYPE", true, true)) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
return chain(doctype(1));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (stream.eat("?")) {
|
||||
stream.eatWhile(/[\w\._\-]/);
|
||||
state.tokenize = inBlock("meta", "?>");
|
||||
return "meta";
|
||||
} else {
|
||||
type = stream.eat("/") ? "closeTag" : "openTag";
|
||||
state.tokenize = inTag;
|
||||
return "tag bracket";
|
||||
}
|
||||
} else if (ch == "&") {
|
||||
var ok;
|
||||
if (stream.eat("#")) {
|
||||
if (stream.eat("x")) {
|
||||
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
|
||||
}
|
||||
} else {
|
||||
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
|
||||
}
|
||||
return ok ? "atom" : "error";
|
||||
} else {
|
||||
stream.eatWhile(/[^&<]/);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
inText.isInText = true;
|
||||
|
||||
function inTag(stream, state) {
|
||||
var ch = stream.next();
|
||||
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
|
||||
state.tokenize = inText;
|
||||
type = ch == ">" ? "endTag" : "selfcloseTag";
|
||||
return "tag bracket";
|
||||
} else if (ch == "=") {
|
||||
type = "equals";
|
||||
return null;
|
||||
} else if (ch == "<") {
|
||||
state.tokenize = inText;
|
||||
state.state = baseState;
|
||||
state.tagName = state.tagStart = null;
|
||||
var next = state.tokenize(stream, state);
|
||||
return next ? next + " tag error" : "tag error";
|
||||
} else if (/[\'\"]/.test(ch)) {
|
||||
state.tokenize = inAttribute(ch);
|
||||
state.stringStartCol = stream.column();
|
||||
return state.tokenize(stream, state);
|
||||
} else {
|
||||
stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
|
||||
return "word";
|
||||
}
|
||||
}
|
||||
|
||||
function inAttribute(quote) {
|
||||
var closure = function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.next() == quote) {
|
||||
state.tokenize = inTag;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "string";
|
||||
};
|
||||
closure.isInAttribute = true;
|
||||
return closure;
|
||||
}
|
||||
|
||||
function inBlock(style, terminator) {
|
||||
return function(stream, state) {
|
||||
while (!stream.eol()) {
|
||||
if (stream.match(terminator)) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
}
|
||||
stream.next();
|
||||
}
|
||||
return style;
|
||||
};
|
||||
}
|
||||
function doctype(depth) {
|
||||
return function(stream, state) {
|
||||
var ch;
|
||||
while ((ch = stream.next()) != null) {
|
||||
if (ch == "<") {
|
||||
state.tokenize = doctype(depth + 1);
|
||||
return state.tokenize(stream, state);
|
||||
} else if (ch == ">") {
|
||||
if (depth == 1) {
|
||||
state.tokenize = inText;
|
||||
break;
|
||||
} else {
|
||||
state.tokenize = doctype(depth - 1);
|
||||
return state.tokenize(stream, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
return "meta";
|
||||
};
|
||||
}
|
||||
|
||||
function Context(state, tagName, startOfLine) {
|
||||
this.prev = state.context;
|
||||
this.tagName = tagName;
|
||||
this.indent = state.indented;
|
||||
this.startOfLine = startOfLine;
|
||||
if (config.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
|
||||
this.noIndent = true;
|
||||
}
|
||||
function popContext(state) {
|
||||
if (state.context) state.context = state.context.prev;
|
||||
}
|
||||
function maybePopContext(state, nextTagName) {
|
||||
var parentTagName;
|
||||
while (true) {
|
||||
if (!state.context) {
|
||||
return;
|
||||
}
|
||||
parentTagName = state.context.tagName;
|
||||
if (!config.contextGrabbers.hasOwnProperty(parentTagName) ||
|
||||
!config.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
|
||||
return;
|
||||
}
|
||||
popContext(state);
|
||||
}
|
||||
}
|
||||
|
||||
function baseState(type, stream, state) {
|
||||
if (type == "openTag") {
|
||||
state.tagStart = stream.column();
|
||||
return tagNameState;
|
||||
} else if (type == "closeTag") {
|
||||
return closeTagNameState;
|
||||
} else {
|
||||
return baseState;
|
||||
}
|
||||
}
|
||||
function tagNameState(type, stream, state) {
|
||||
if (type == "word") {
|
||||
state.tagName = stream.current();
|
||||
setStyle = "tag";
|
||||
return attrState;
|
||||
} else {
|
||||
setStyle = "error";
|
||||
return tagNameState;
|
||||
}
|
||||
}
|
||||
function closeTagNameState(type, stream, state) {
|
||||
if (type == "word") {
|
||||
var tagName = stream.current();
|
||||
if (state.context && state.context.tagName != tagName &&
|
||||
config.implicitlyClosed.hasOwnProperty(state.context.tagName))
|
||||
popContext(state);
|
||||
if ((state.context && state.context.tagName == tagName) || config.matchClosing === false) {
|
||||
setStyle = "tag";
|
||||
return closeState;
|
||||
} else {
|
||||
setStyle = "tag error";
|
||||
return closeStateErr;
|
||||
}
|
||||
} else {
|
||||
setStyle = "error";
|
||||
return closeStateErr;
|
||||
}
|
||||
}
|
||||
|
||||
function closeState(type, _stream, state) {
|
||||
if (type != "endTag") {
|
||||
setStyle = "error";
|
||||
return closeState;
|
||||
}
|
||||
popContext(state);
|
||||
return baseState;
|
||||
}
|
||||
function closeStateErr(type, stream, state) {
|
||||
setStyle = "error";
|
||||
return closeState(type, stream, state);
|
||||
}
|
||||
|
||||
function attrState(type, _stream, state) {
|
||||
if (type == "word") {
|
||||
setStyle = "attribute";
|
||||
return attrEqState;
|
||||
} else if (type == "endTag" || type == "selfcloseTag") {
|
||||
var tagName = state.tagName, tagStart = state.tagStart;
|
||||
state.tagName = state.tagStart = null;
|
||||
if (type == "selfcloseTag" ||
|
||||
config.autoSelfClosers.hasOwnProperty(tagName)) {
|
||||
maybePopContext(state, tagName);
|
||||
} else {
|
||||
maybePopContext(state, tagName);
|
||||
state.context = new Context(state, tagName, tagStart == state.indented);
|
||||
}
|
||||
return baseState;
|
||||
}
|
||||
setStyle = "error";
|
||||
return attrState;
|
||||
}
|
||||
function attrEqState(type, stream, state) {
|
||||
if (type == "equals") return attrValueState;
|
||||
if (!config.allowMissing) setStyle = "error";
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attrValueState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
if (type == "word" && config.allowUnquoted) {setStyle = "string"; return attrState;}
|
||||
setStyle = "error";
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
function attrContinuedState(type, stream, state) {
|
||||
if (type == "string") return attrContinuedState;
|
||||
return attrState(type, stream, state);
|
||||
}
|
||||
|
||||
return {
|
||||
startState: function(baseIndent) {
|
||||
var state = {tokenize: inText,
|
||||
state: baseState,
|
||||
indented: baseIndent || 0,
|
||||
tagName: null, tagStart: null,
|
||||
context: null}
|
||||
if (baseIndent != null) state.baseIndent = baseIndent
|
||||
return state
|
||||
},
|
||||
|
||||
token: function(stream, state) {
|
||||
if (!state.tagName && stream.sol())
|
||||
state.indented = stream.indentation();
|
||||
|
||||
if (stream.eatSpace()) return null;
|
||||
type = null;
|
||||
var style = state.tokenize(stream, state);
|
||||
if ((style || type) && style != "comment") {
|
||||
setStyle = null;
|
||||
state.state = state.state(type || style, stream, state);
|
||||
if (setStyle)
|
||||
style = setStyle == "error" ? style + " error" : setStyle;
|
||||
}
|
||||
return style;
|
||||
},
|
||||
|
||||
indent: function(state, textAfter, fullLine) {
|
||||
var context = state.context;
|
||||
// Indent multi-line strings (e.g. css).
|
||||
if (state.tokenize.isInAttribute) {
|
||||
if (state.tagStart == state.indented)
|
||||
return state.stringStartCol + 1;
|
||||
else
|
||||
return state.indented + indentUnit;
|
||||
}
|
||||
if (context && context.noIndent) return CodeMirror.Pass;
|
||||
if (state.tokenize != inTag && state.tokenize != inText)
|
||||
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
|
||||
// Indent the starts of attribute names.
|
||||
if (state.tagName) {
|
||||
if (config.multilineTagIndentPastTag !== false)
|
||||
return state.tagStart + state.tagName.length + 2;
|
||||
else
|
||||
return state.tagStart + indentUnit * (config.multilineTagIndentFactor || 1);
|
||||
}
|
||||
if (config.alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
|
||||
var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
|
||||
if (tagAfter && tagAfter[1]) { // Closing tag spotted
|
||||
while (context) {
|
||||
if (context.tagName == tagAfter[2]) {
|
||||
context = context.prev;
|
||||
break;
|
||||
} else if (config.implicitlyClosed.hasOwnProperty(context.tagName)) {
|
||||
context = context.prev;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (tagAfter) { // Opening tag spotted
|
||||
while (context) {
|
||||
var grabbers = config.contextGrabbers[context.tagName];
|
||||
if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
|
||||
context = context.prev;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (context && context.prev && !context.startOfLine)
|
||||
context = context.prev;
|
||||
if (context) return context.indent + indentUnit;
|
||||
else return state.baseIndent || 0;
|
||||
},
|
||||
|
||||
electricInput: /<\/[\s\w:]+>$/,
|
||||
blockCommentStart: "<!--",
|
||||
blockCommentEnd: "-->",
|
||||
|
||||
configuration: config.htmlMode ? "html" : "xml",
|
||||
helperType: config.htmlMode ? "html" : "xml",
|
||||
|
||||
skipAttribute: function(state) {
|
||||
if (state.state == attrValueState)
|
||||
state.state = attrState
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.defineMIME("text/xml", "xml");
|
||||
CodeMirror.defineMIME("application/xml", "xml");
|
||||
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
|
||||
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
|
||||
|
||||
});
|
||||
60
docs/tips/15-expose-component-functions.zh-CN.md
Normal file
60
docs/tips/15-expose-component-functions.zh-CN.md
Normal file
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: expose-component-functions-zh-CN
|
||||
title: 暴露组件函数
|
||||
layout: tips
|
||||
permalink: tips/expose-component-functions-zh-CN.html
|
||||
prev: communicate-between-components-zh-CN.html
|
||||
next: children-undefined-zh-CN.html
|
||||
---
|
||||
|
||||
|
||||
这是另外一种组件[通信的方法](/react/tips/communicate-between-components.html):在子组件中暴露出一个方法,可以让父组件去调。
|
||||
|
||||
让我们看看这个todos的列表,在点击的时候就会被移除。如果只剩下最后一个未完成的待办事项,就执行animate函数:
|
||||
|
||||
```js
|
||||
var Todo = React.createClass({
|
||||
render: function() {
|
||||
return <div onClick={this.props.onClick}>{this.props.title}</div>;
|
||||
},
|
||||
|
||||
//this component will be accessed by the parent through the `ref` attribute
|
||||
animate: function() {
|
||||
console.log('Pretend %s is animating', this.props.title);
|
||||
}
|
||||
});
|
||||
|
||||
var Todos = React.createClass({
|
||||
getInitialState: function() {
|
||||
return {items: ['Apple', 'Banana', 'Cranberry']};
|
||||
},
|
||||
|
||||
handleClick: function(index) {
|
||||
var items = this.state.items.filter(function(item, i) {
|
||||
return index !== i;
|
||||
});
|
||||
this.setState({items: items}, function() {
|
||||
if (items.length === 1) {
|
||||
this.refs.item0.animate();
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.items.map(function(item, i) {
|
||||
var boundClick = this.handleClick.bind(this, i);
|
||||
return (
|
||||
<Todo onClick={boundClick} key={i} title={item} ref={'item' + i} />
|
||||
);
|
||||
}, this)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
ReactDOM.render(<Todos />, mountNode);
|
||||
```
|
||||
|
||||
当然,你也可以通过在`todo`组件中的prop传递`isLastUnfinishedItem`,来让子组件在 `componentDidUpdate`中判断是否它是最后一个,来执行animate函数;但是,如果你通过不同的props值来控制的不同的动画,到最后可能会变得很混乱。
|
||||
@@ -24,4 +24,4 @@ Only a ReactOwner can have refs. This usually means that you're trying to add a
|
||||
|
||||
Bower does a good job of deduplicating dependencies, but NPM does not. If you aren't doing anything (fancy) with refs, there is a good chance that the problem is not with your refs, but rather an issue with having multiple copies of React loaded into your project. Sometimes, when you pull in a third-party module via npm, you will get a duplicate copy of the dependency library, and this can create problems.
|
||||
|
||||
If you are using npm... `npm ls` or `npm ls | grep react` might help illuminate.
|
||||
If you are using npm... `npm ls` or `npm ls react` might help illuminate.
|
||||
|
||||
@@ -44,6 +44,7 @@ var addons = {
|
||||
shallowCompare: {
|
||||
module: 'shallowCompare',
|
||||
name: 'shallow-compare',
|
||||
docs: 'shallow-compare',
|
||||
},
|
||||
updates: {
|
||||
module: 'update',
|
||||
|
||||
2
npm-shrinkwrap.json
generated
2
npm-shrinkwrap.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-build",
|
||||
"version": "15.3.1",
|
||||
"version": "15.3.2",
|
||||
"dependencies": {
|
||||
"art": {
|
||||
"version": "0.10.1",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react-build",
|
||||
"private": true,
|
||||
"version": "15.3.1",
|
||||
"version": "15.3.2",
|
||||
"devDependencies": {
|
||||
"art": "^0.10.1",
|
||||
"async": "^1.5.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-addons-template",
|
||||
"version": "15.3.1",
|
||||
"version": "15.3.2",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
"keywords": [
|
||||
@@ -10,7 +10,7 @@
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"react": "^15.3.1"
|
||||
"react": "^15.3.2"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-dom",
|
||||
"version": "15.3.1",
|
||||
"version": "15.3.2",
|
||||
"description": "React package for working with the DOM.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -14,7 +14,7 @@
|
||||
"homepage": "https://facebook.github.io/react/",
|
||||
"dependencies": {},
|
||||
"peerDependencies": {
|
||||
"react": "^15.3.1"
|
||||
"react": "^15.3.2"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-renderer",
|
||||
"version": "15.3.1",
|
||||
"version": "15.3.2",
|
||||
"description": "React package for use inside react-native.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"homepage": "https://facebook.github.io/react-native/",
|
||||
"dependencies": {
|
||||
"react": "^15.3.1"
|
||||
"react": "^15.3.2"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-test-renderer",
|
||||
"version": "15.3.1",
|
||||
"version": "15.3.2",
|
||||
"description": "React package for snapshot testing.",
|
||||
"main": "index.js",
|
||||
"repository": "facebook/react",
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"homepage": "https://facebook.github.io/react/",
|
||||
"peerDependencies": {
|
||||
"react": "^15.3.1"
|
||||
"react": "^15.3.2"
|
||||
},
|
||||
"files": [
|
||||
"LICENSE",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "react",
|
||||
"description": "React is a JavaScript library for building user interfaces.",
|
||||
"version": "15.3.1",
|
||||
"version": "15.3.2",
|
||||
"keywords": [
|
||||
"react"
|
||||
],
|
||||
@@ -31,5 +31,10 @@
|
||||
"transform": [
|
||||
"loose-envify"
|
||||
]
|
||||
},
|
||||
"node-haste" {
|
||||
"roots": [
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,12 @@
|
||||
module.exports = function autoImporter(babel) {
|
||||
const t = babel.types;
|
||||
|
||||
function getAssignIdent(path, file, state) {
|
||||
function isObjectAssign(file) {
|
||||
var filename = file.opts.filename;
|
||||
return filename.indexOf('object-assign') >= 0;
|
||||
}
|
||||
|
||||
function getAssignIdent(path, state) {
|
||||
if (!state.id) {
|
||||
state.id = path.scope.generateUidIdentifier('assign');
|
||||
path.scope.getProgramParent().push({
|
||||
@@ -33,17 +38,19 @@ module.exports = function autoImporter(babel) {
|
||||
},
|
||||
|
||||
visitor: {
|
||||
CallExpression: function(path, file) {
|
||||
CallExpression: function(path, state) {
|
||||
if (isObjectAssign(state.file)) { return }
|
||||
if (path.get('callee').matchesPattern('Object.assign')) {
|
||||
// generate identifier and require if it hasn't been already
|
||||
var id = getAssignIdent(path, file, this);
|
||||
var id = getAssignIdent(path, state);
|
||||
path.node.callee = id;
|
||||
}
|
||||
},
|
||||
|
||||
MemberExpression: function(path, file) {
|
||||
MemberExpression: function(path, state) {
|
||||
if (isObjectAssign(state.file)) { return }
|
||||
if (path.matchesPattern('Object.assign')) {
|
||||
var id = getAssignIdent(path, file, this);
|
||||
var id = getAssignIdent(path, state);
|
||||
path.replaceWith(id);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = '15.3.1';
|
||||
module.exports = '15.3.2';
|
||||
|
||||
@@ -204,16 +204,6 @@ ReactElement.createElement = function(type, config, children) {
|
||||
var source = null;
|
||||
|
||||
if (config != null) {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
/* eslint-disable no-proto */
|
||||
config.__proto__ == null || config.__proto__ === Object.prototype,
|
||||
/* eslint-enable no-proto */
|
||||
'React.createElement(...): Expected props argument to be a plain object. ' +
|
||||
'Properties defined in its prototype chain will be ignored.'
|
||||
);
|
||||
}
|
||||
|
||||
if (hasValidRef(config)) {
|
||||
ref = config.ref;
|
||||
}
|
||||
@@ -334,16 +324,6 @@ ReactElement.cloneElement = function(element, config, children) {
|
||||
var owner = element._owner;
|
||||
|
||||
if (config != null) {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
/* eslint-disable no-proto */
|
||||
config.__proto__ == null || config.__proto__ === Object.prototype,
|
||||
/* eslint-enable no-proto */
|
||||
'React.cloneElement(...): Expected props argument to be a plain object. ' +
|
||||
'Properties defined in its prototype chain will be ignored.'
|
||||
);
|
||||
}
|
||||
|
||||
if (hasValidRef(config)) {
|
||||
// Silently steal the ref from the parent.
|
||||
ref = config.ref;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user