├── .gitignore ├── README.md ├── flux-demo ├── README.md ├── flux-demo-server │ ├── index.js │ ├── package.json │ └── route │ │ └── index.js └── flux-demo-static │ ├── gulpfile.js │ ├── package.json │ └── src │ ├── css │ └── bootstrap.css │ ├── index.html │ └── js │ ├── action │ └── flux-demo.js │ ├── component │ ├── content.js │ ├── dropdown.js │ └── flux-demo.js │ ├── dispatcher │ └── dispatcher.js │ ├── lib │ ├── babel-external-helpers.js │ ├── event-emitter.js │ ├── fetch.js │ ├── flux.js │ ├── promise.js │ └── react.js │ └── store │ └── flux-demo.js └── react-router-demo ├── .gitignore ├── README.md ├── gulpfile.js ├── package.json └── src ├── index.html └── js ├── component ├── about.js ├── app.js ├── concat.js └── list.js └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | flux-demo/flux-demo-static/node_modules/ 2 | flux-demo/flux-demo-server/node_modules/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Demo 2 | 3 | 我的博客中 [React 系列文章](http://stylechen.com/category/react) 中的 Demo 都在本项目中。 -------------------------------------------------------------------------------- /flux-demo/README.md: -------------------------------------------------------------------------------- 1 | # Flux Demo 2 | 3 | `flux-demo-server` 为 node 服务,提供测试数据。 4 | 5 | `flux-demo-static` 为前端部分,Demo 代码都在这个文件夹下。 6 | 7 | ### 启动项目 8 | 9 | 分别进入 2 个目录,执行 `npm install` 安装依赖,依赖安装结束后执行 `npm start` 就启动了项目,在浏览器中输入 `http://127.0.0.1:3001` 即可访问。 10 | 11 | 本 Demo 在 [React 应用的架构模式 Flux](http://stylechen.com/react-flux.html) 有详细的讲解。 12 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-server/index.js: -------------------------------------------------------------------------------- 1 | var koa = require( 'koa' ); 2 | var logger = require( 'koa-logger' ); 3 | var router = require( 'koa-router' )(); 4 | var indexRoute = require( './route/index' ); 5 | 6 | var app = koa(); 7 | 8 | app.use( logger() ); 9 | 10 | indexRoute( router ); 11 | 12 | app.use(router.routes()); 13 | 14 | app.listen( 3002, '127.0.0.1' ); 15 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fulx-demo-server", 3 | "version": "0.1.0", 4 | "author": "chenmnkken@jumei.com", 5 | "engines": { 6 | "node": ">= 0.8.0" 7 | }, 8 | "scripts": { 9 | "start": "DEBUG=koa* node --harmony index.js", 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "dependencies": { 13 | "koa": "1.0.0", 14 | "koa-logger": "1.3.0", 15 | "koa-router": "5.2.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-server/route/index.js: -------------------------------------------------------------------------------- 1 | var mockData = { 2 | react: 'React is a JavaScript library for building user interfaces.', 3 | 4 | angular: 'Angular is a development platform for building mobile and desktop web applications. This is the repository for Angular 2, both the JavaScript (JS) and Dart versions.', 5 | 6 | polymer: 'Polymer lets you build encapsulated, re-usable elements that work just like HTML elements, to use in building web applications.' 7 | }; 8 | 9 | var index = function(router){ 10 | router.get('/api/:browsers', function* (){ 11 | this.set('Access-Control-Allow-Methods', 'GET,POST,OPTIONS,PUT,DELETE'); 12 | this.set('Access-Control-Allow-Origin', '*'); 13 | this.type = 'application/json'; 14 | this.body = { 15 | data: mockData[this.params.browsers] 16 | } 17 | }); 18 | }; 19 | 20 | module.exports = index; 21 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var gutil = require('gulp-util'); 3 | var babelify = require('babelify'); 4 | var browserify = require('browserify'); 5 | var watchify = require('watchify'); 6 | var cacheify = require('cacheify'); 7 | var levelup = require('levelup'); 8 | var source = require('vinyl-source-stream'); 9 | var less = require('gulp-less'); 10 | var connect = require('gulp-connect'); 11 | var LessPluginAutoPrefix = require('less-plugin-autoprefix'); 12 | var autoprefix= new LessPluginAutoPrefix({ browsers: ['last 2 versions'] }); 13 | var db = levelup('./.cache'); 14 | 15 | var srcRoot = 'src'; 16 | var jsSrcPath = './src/js/component/flux-demo.js'; 17 | var jsDestPath = './src/js'; 18 | 19 | var browserOpts = { 20 | entries: [jsSrcPath], 21 | debug: true, 22 | insertGlobals: true, 23 | detectGlobals: false 24 | }; 25 | 26 | gulp.task('connect', function () { 27 | connect.server({ 28 | root: [srcRoot], 29 | port: 3001, 30 | livereload: true, 31 | fallback: 'src/index.html' 32 | }); 33 | }); 34 | 35 | gulp.task('watch-html', function () { 36 | gulp.watch(srcRoot + '/**/*.html', function () { 37 | return gulp.src(srcRoot + '/**/*.html') 38 | .pipe(connect.reload()); 39 | }); 40 | }); 41 | 42 | var bundle = function () { 43 | return watcher.bundle() 44 | .on('error', function (err) { 45 | console.log(err.message); 46 | console.log(err.stack); 47 | }) 48 | .pipe(source('bundle.js')) 49 | .pipe(gulp.dest(jsDestPath)) 50 | .pipe(connect.reload()); 51 | }; 52 | 53 | var babelifyCache = cacheify(babelify.configure({ 54 | externalHelpers: true, 55 | stage: 0 56 | }), db); 57 | 58 | var bundler = browserify(browserOpts) 59 | .transform(babelifyCache); 60 | 61 | var watcher = watchify(bundler) 62 | .on('update', bundle) 63 | .on('log', gutil.log); 64 | 65 | gulp.task('watch-js', bundle); 66 | gulp.task('watch', ['watch-js', 'watch-html']) 67 | gulp.task('default', ['connect', 'watch']); 68 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "flux-demo-static", 3 | "version": "0.1.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "gulp", 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "chenmnkken@gmail.com", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "babelify": "6.1.2", 13 | "browserify": "10.2.4", 14 | "cacheify": "0.4.1", 15 | "gulp": "3.9.0", 16 | "gulp-connect": "2.2.0", 17 | "gulp-less": "3.0.3", 18 | "gulp-util": "3.0.5", 19 | "less-plugin-autoprefix": "1.4.2", 20 | "leveldown": "1.4.1", 21 | "levelup": "1.2.1", 22 | "vinyl-source-stream": "1.1.0", 23 | "watchify": "3.2.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Flux Demo 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/action/flux-demo.js: -------------------------------------------------------------------------------- 1 | import dispatcher from '../dispatcher/dispatcher'; 2 | 3 | const fluxDemoActions = { 4 | fetchIntroduction (name, path) { 5 | const url = `http://127.0.0.1:3002${path}`; 6 | 7 | dispatcher.dispatchAsync(url, { 8 | request: 'FETCH_INTRODUCTION', 9 | success: 'FETCH_INTRODUCTION_SUCCESS', 10 | failure: 'FETCH_INTRODUCTION_ERROR' 11 | },{ 12 | name 13 | }); 14 | } 15 | }; 16 | 17 | export default fluxDemoActions; 18 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/component/content.js: -------------------------------------------------------------------------------- 1 | import fluxDemoStore from '../store/flux-demo'; 2 | 3 | class Content extends React.Component { 4 | constructor (props) { 5 | super(props); 6 | 7 | this.state = {}; 8 | } 9 | 10 | componentDidMount () { 11 | fluxDemoStore.on('change', this.refreshContent); 12 | } 13 | 14 | componentWillUnmount () { 15 | fluxDemoStore.off('change', this.refreshContent); 16 | } 17 | 18 | refreshContent = () => { 19 | const introduction = fluxDemoStore.getIntroduction(this.props.name); 20 | 21 | this.setState({ 22 | introduction 23 | }); 24 | } 25 | 26 | render () { 27 | const boxStyle = { 28 | padding: '20px 0', 29 | fontSize: '14px' 30 | }; 31 | 32 | return ( 33 |
34 |

{this.state.introduction}

35 |
36 | ); 37 | } 38 | }; 39 | 40 | export default Content; 41 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/component/dropdown.js: -------------------------------------------------------------------------------- 1 | class Dropdown extends React.Component { 2 | constructor (props) { 3 | super(props); 4 | this.state = { 5 | visibile: false, 6 | btnText: this.props.btnText 7 | }; 8 | } 9 | 10 | onBtnClick = () => { 11 | this.setState({ 12 | visible: !this.state.visible 13 | }); 14 | } 15 | 16 | onItemClick = (event) => { 17 | const target = event.target; 18 | const url = target.dataset.url; 19 | const text = target.textContent; 20 | 21 | this.setState({ 22 | visible: false, 23 | btnText: text 24 | }); 25 | 26 | if (this.props.selectCallback) { 27 | this.props.selectCallback(text); 28 | } 29 | 30 | event.preventDefault(); 31 | } 32 | 33 | render () { 34 | const displayValue = this.state.visible ? 'block' : 'none'; 35 | 36 | return ( 37 |
38 | 39 | 50 |
51 | ); 52 | } 53 | }; 54 | 55 | export default Dropdown; 56 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/component/flux-demo.js: -------------------------------------------------------------------------------- 1 | import Dropdown from './dropdown'; 2 | import Content from './content'; 3 | import fluxDemoActions from '../action/flux-demo'; 4 | 5 | class FluxDemo extends React.Component { 6 | constructor (props) { 7 | super(props); 8 | 9 | this.state = {}; 10 | } 11 | 12 | static defaultProps = { 13 | dropdownBtn: 'JavaScript library', 14 | dropdownItems: [ 15 | { text: 'React', url: '/api/react' }, 16 | { text: 'Angular', url: '/api/angular' }, 17 | { text: 'Polymer', url: '/api/polymer' } 18 | ] 19 | } 20 | 21 | selectCallback = (name) => { 22 | const path = `/api/${name.toLowerCase()}`; 23 | 24 | this.setState({ 25 | selected: name 26 | }, () => { 27 | fluxDemoActions.fetchIntroduction(name, path); 28 | }); 29 | } 30 | 31 | render () { 32 | return ( 33 |
34 |

This is a Flux demo.

35 | 39 | 40 |
41 | ) 42 | } 43 | }; 44 | 45 | React.render( 46 | , 47 | document.getElementById('root') 48 | ); 49 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/dispatcher/dispatcher.js: -------------------------------------------------------------------------------- 1 | class Dispatcher extends Flux.Dispatcher { 2 | constructor (...args) { 3 | super(...args); 4 | } 5 | 6 | dispatch (type, action = {}) { 7 | if (!type) { 8 | throw new Error('You forgot to specify type.'); 9 | } 10 | 11 | super.dispatch({type, ...action}); 12 | } 13 | 14 | dispatchAsync (url, types, action = {}) { 15 | const { request, success, failure } = types; 16 | const promise = fetch(url).then((response) => response.json()); 17 | this.dispatch(request, action); 18 | 19 | promise.then( 20 | (response) => { 21 | this.dispatch(success, {...action, response}); 22 | }, 23 | 24 | (error) => { 25 | this.dispatch(failure, {...action, error}); 26 | } 27 | ); 28 | } 29 | }; 30 | 31 | export default new Dispatcher(); 32 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/lib/babel-external-helpers.js: -------------------------------------------------------------------------------- 1 | (function (global) { 2 | var babelHelpers = global.babelHelpers = {}; 3 | 4 | babelHelpers.inherits = function (subClass, superClass) { 5 | if (typeof superClass !== "function" && superClass !== null) { 6 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); 7 | } 8 | 9 | subClass.prototype = Object.create(superClass && superClass.prototype, { 10 | constructor: { 11 | value: subClass, 12 | enumerable: false, 13 | writable: true, 14 | configurable: true 15 | } 16 | }); 17 | if (superClass) subClass.__proto__ = superClass; 18 | }; 19 | 20 | babelHelpers.defaults = function (obj, defaults) { 21 | var keys = Object.getOwnPropertyNames(defaults); 22 | 23 | for (var i = 0; i < keys.length; i++) { 24 | var key = keys[i]; 25 | var value = Object.getOwnPropertyDescriptor(defaults, key); 26 | 27 | if (value && value.configurable && obj[key] === undefined) { 28 | Object.defineProperty(obj, key, value); 29 | } 30 | } 31 | 32 | return obj; 33 | }; 34 | 35 | babelHelpers.createClass = (function () { 36 | function defineProperties(target, props) { 37 | for (var i = 0; i < props.length; i++) { 38 | var descriptor = props[i]; 39 | descriptor.enumerable = descriptor.enumerable || false; 40 | descriptor.configurable = true; 41 | if ("value" in descriptor) descriptor.writable = true; 42 | Object.defineProperty(target, descriptor.key, descriptor); 43 | } 44 | } 45 | 46 | return function (Constructor, protoProps, staticProps) { 47 | if (protoProps) defineProperties(Constructor.prototype, protoProps); 48 | if (staticProps) defineProperties(Constructor, staticProps); 49 | return Constructor; 50 | }; 51 | })(); 52 | 53 | babelHelpers.createDecoratedClass = (function () { 54 | function defineProperties(target, descriptors, initializers) { 55 | for (var i = 0; i < descriptors.length; i++) { 56 | var descriptor = descriptors[i]; 57 | var decorators = descriptor.decorators; 58 | var key = descriptor.key; 59 | delete descriptor.key; 60 | delete descriptor.decorators; 61 | descriptor.enumerable = descriptor.enumerable || false; 62 | descriptor.configurable = true; 63 | if ("value" in descriptor || descriptor.initializer) descriptor.writable = true; 64 | 65 | if (decorators) { 66 | for (var f = 0; f < decorators.length; f++) { 67 | var decorator = decorators[f]; 68 | 69 | if (typeof decorator === "function") { 70 | descriptor = decorator(target, key, descriptor) || descriptor; 71 | } else { 72 | throw new TypeError("The decorator for method " + descriptor.key + " is of the invalid type " + typeof decorator); 73 | } 74 | } 75 | 76 | if (descriptor.initializer !== undefined) { 77 | initializers[key] = descriptor; 78 | continue; 79 | } 80 | } 81 | 82 | Object.defineProperty(target, key, descriptor); 83 | } 84 | } 85 | 86 | return function (Constructor, protoProps, staticProps, protoInitializers, staticInitializers) { 87 | if (protoProps) defineProperties(Constructor.prototype, protoProps, protoInitializers); 88 | if (staticProps) defineProperties(Constructor, staticProps, staticInitializers); 89 | return Constructor; 90 | }; 91 | })(); 92 | 93 | babelHelpers.createDecoratedObject = function (descriptors) { 94 | var target = {}; 95 | 96 | for (var i = 0; i < descriptors.length; i++) { 97 | var descriptor = descriptors[i]; 98 | var decorators = descriptor.decorators; 99 | var key = descriptor.key; 100 | delete descriptor.key; 101 | delete descriptor.decorators; 102 | descriptor.enumerable = true; 103 | descriptor.configurable = true; 104 | if ("value" in descriptor || descriptor.initializer) descriptor.writable = true; 105 | 106 | if (decorators) { 107 | for (var f = 0; f < decorators.length; f++) { 108 | var decorator = decorators[f]; 109 | 110 | if (typeof decorator === "function") { 111 | descriptor = decorator(target, key, descriptor) || descriptor; 112 | } else { 113 | throw new TypeError("The decorator for method " + descriptor.key + " is of the invalid type " + typeof decorator); 114 | } 115 | } 116 | } 117 | 118 | if (descriptor.initializer) { 119 | descriptor.value = descriptor.initializer.call(target); 120 | } 121 | 122 | Object.defineProperty(target, key, descriptor); 123 | } 124 | 125 | return target; 126 | }; 127 | 128 | babelHelpers.defineDecoratedPropertyDescriptor = function (target, key, descriptors) { 129 | var _descriptor = descriptors[key]; 130 | if (!_descriptor) return; 131 | var descriptor = {}; 132 | 133 | for (var _key in _descriptor) descriptor[_key] = _descriptor[_key]; 134 | 135 | descriptor.value = descriptor.initializer.call(target); 136 | Object.defineProperty(target, key, descriptor); 137 | }; 138 | 139 | babelHelpers.taggedTemplateLiteral = function (strings, raw) { 140 | return Object.freeze(Object.defineProperties(strings, { 141 | raw: { 142 | value: Object.freeze(raw) 143 | } 144 | })); 145 | }; 146 | 147 | babelHelpers.taggedTemplateLiteralLoose = function (strings, raw) { 148 | strings.raw = raw; 149 | return strings; 150 | }; 151 | 152 | babelHelpers.toArray = function (arr) { 153 | return Array.isArray(arr) ? arr : Array.from(arr); 154 | }; 155 | 156 | babelHelpers.toConsumableArray = function (arr) { 157 | if (Array.isArray(arr)) { 158 | for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; 159 | 160 | return arr2; 161 | } else { 162 | return Array.from(arr); 163 | } 164 | }; 165 | 166 | babelHelpers.slicedToArray = (function () { 167 | function sliceIterator(arr, i) { 168 | var _arr = []; 169 | var _n = true; 170 | var _d = false; 171 | var _e = undefined; 172 | 173 | try { 174 | for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { 175 | _arr.push(_s.value); 176 | 177 | if (i && _arr.length === i) break; 178 | } 179 | } catch (err) { 180 | _d = true; 181 | _e = err; 182 | } finally { 183 | try { 184 | if (!_n && _i["return"]) _i["return"](); 185 | } finally { 186 | if (_d) throw _e; 187 | } 188 | } 189 | 190 | return _arr; 191 | } 192 | 193 | return function (arr, i) { 194 | if (Array.isArray(arr)) { 195 | return arr; 196 | } else if (Symbol.iterator in Object(arr)) { 197 | return sliceIterator(arr, i); 198 | } else { 199 | throw new TypeError("Invalid attempt to destructure non-iterable instance"); 200 | } 201 | }; 202 | })(); 203 | 204 | babelHelpers.slicedToArrayLoose = function (arr, i) { 205 | if (Array.isArray(arr)) { 206 | return arr; 207 | } else if (Symbol.iterator in Object(arr)) { 208 | var _arr = []; 209 | 210 | for (var _iterator = arr[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) { 211 | _arr.push(_step.value); 212 | 213 | if (i && _arr.length === i) break; 214 | } 215 | 216 | return _arr; 217 | } else { 218 | throw new TypeError("Invalid attempt to destructure non-iterable instance"); 219 | } 220 | }; 221 | 222 | babelHelpers.objectWithoutProperties = function (obj, keys) { 223 | var target = {}; 224 | 225 | for (var i in obj) { 226 | if (keys.indexOf(i) >= 0) continue; 227 | if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; 228 | target[i] = obj[i]; 229 | } 230 | 231 | return target; 232 | }; 233 | 234 | babelHelpers.hasOwn = Object.prototype.hasOwnProperty; 235 | babelHelpers.slice = Array.prototype.slice; 236 | babelHelpers.bind = Function.prototype.bind; 237 | 238 | babelHelpers.defineProperty = function (obj, key, value) { 239 | if (key in obj) { 240 | Object.defineProperty(obj, key, { 241 | value: value, 242 | enumerable: true, 243 | configurable: true, 244 | writable: true 245 | }); 246 | } else { 247 | obj[key] = value; 248 | } 249 | 250 | return obj; 251 | }; 252 | 253 | babelHelpers.asyncToGenerator = function (fn) { 254 | return function () { 255 | var gen = fn.apply(this, arguments); 256 | return new Promise(function (resolve, reject) { 257 | var callNext = step.bind(null, "next"); 258 | var callThrow = step.bind(null, "throw"); 259 | 260 | function step(key, arg) { 261 | try { 262 | var info = gen[key](arg); 263 | var value = info.value; 264 | } catch (error) { 265 | reject(error); 266 | return; 267 | } 268 | 269 | if (info.done) { 270 | resolve(value); 271 | } else { 272 | Promise.resolve(value).then(callNext, callThrow); 273 | } 274 | } 275 | 276 | callNext(); 277 | }); 278 | }; 279 | }; 280 | 281 | babelHelpers.interopRequireWildcard = function (obj) { 282 | if (obj && obj.__esModule) { 283 | return obj; 284 | } else { 285 | var newObj = {}; 286 | 287 | if (obj != null) { 288 | for (var key in obj) { 289 | if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; 290 | } 291 | } 292 | 293 | newObj["default"] = obj; 294 | return newObj; 295 | } 296 | }; 297 | 298 | babelHelpers.interopRequireDefault = function (obj) { 299 | return obj && obj.__esModule ? obj : { 300 | "default": obj 301 | }; 302 | }; 303 | 304 | babelHelpers._typeof = function (obj) { 305 | return obj && obj.constructor === Symbol ? "symbol" : typeof obj; 306 | }; 307 | 308 | babelHelpers._extends = Object.assign || function (target) { 309 | for (var i = 1; i < arguments.length; i++) { 310 | var source = arguments[i]; 311 | 312 | for (var key in source) { 313 | if (Object.prototype.hasOwnProperty.call(source, key)) { 314 | target[key] = source[key]; 315 | } 316 | } 317 | } 318 | 319 | return target; 320 | }; 321 | 322 | babelHelpers.get = function get(object, property, receiver) { 323 | if (object === null) object = Function.prototype; 324 | var desc = Object.getOwnPropertyDescriptor(object, property); 325 | 326 | if (desc === undefined) { 327 | var parent = Object.getPrototypeOf(object); 328 | 329 | if (parent === null) { 330 | return undefined; 331 | } else { 332 | return get(parent, property, receiver); 333 | } 334 | } else if ("value" in desc) { 335 | return desc.value; 336 | } else { 337 | var getter = desc.get; 338 | 339 | if (getter === undefined) { 340 | return undefined; 341 | } 342 | 343 | return getter.call(receiver); 344 | } 345 | }; 346 | 347 | babelHelpers.set = function set(object, property, value, receiver) { 348 | var desc = Object.getOwnPropertyDescriptor(object, property); 349 | 350 | if (desc === undefined) { 351 | var parent = Object.getPrototypeOf(object); 352 | 353 | if (parent !== null) { 354 | set(parent, property, value, receiver); 355 | } 356 | } else if ("value" in desc && desc.writable) { 357 | desc.value = value; 358 | } else { 359 | var setter = desc.set; 360 | 361 | if (setter !== undefined) { 362 | setter.call(receiver, value); 363 | } 364 | } 365 | 366 | return value; 367 | }; 368 | 369 | babelHelpers.classCallCheck = function (instance, Constructor) { 370 | if (!(instance instanceof Constructor)) { 371 | throw new TypeError("Cannot call a class as a function"); 372 | } 373 | }; 374 | 375 | babelHelpers.objectDestructuringEmpty = function (obj) { 376 | if (obj == null) throw new TypeError("Cannot destructure undefined"); 377 | }; 378 | 379 | babelHelpers.temporalUndefined = {}; 380 | 381 | babelHelpers.temporalAssertDefined = function (val, name, undef) { 382 | if (val === undef) { 383 | throw new ReferenceError(name + " is not defined - temporal dead zone"); 384 | } 385 | 386 | return true; 387 | }; 388 | 389 | babelHelpers.selfGlobal = typeof global === "undefined" ? self : global; 390 | 391 | babelHelpers.defaultProps = function (defaultProps, props) { 392 | if (defaultProps) { 393 | for (var propName in defaultProps) { 394 | if (typeof props[propName] === "undefined") { 395 | props[propName] = defaultProps[propName]; 396 | } 397 | } 398 | } 399 | 400 | return props; 401 | }; 402 | 403 | babelHelpers._instanceof = function (left, right) { 404 | if (right != null && right[Symbol.hasInstance]) { 405 | return right[Symbol.hasInstance](left); 406 | } else { 407 | return left instanceof right; 408 | } 409 | }; 410 | 411 | babelHelpers.interopRequire = function (obj) { 412 | return obj && obj.__esModule ? obj["default"] : obj; 413 | }; 414 | })(typeof global === "undefined" ? self : global); 415 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/lib/event-emitter.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * EventEmitter v4.2.11 - git.io/ee 3 | * Unlicense - http://unlicense.org/ 4 | * Oliver Caldwell - http://oli.me.uk/ 5 | * @preserve 6 | */ 7 | 8 | ;(function () { 9 | 'use strict'; 10 | 11 | /** 12 | * Class for managing events. 13 | * Can be extended to provide event functionality in other classes. 14 | * 15 | * @class EventEmitter Manages event registering and emitting. 16 | */ 17 | function EventEmitter() {} 18 | 19 | // Shortcuts to improve speed and size 20 | var proto = EventEmitter.prototype; 21 | var exports = this; 22 | var originalGlobalValue = exports.EventEmitter; 23 | 24 | /** 25 | * Finds the index of the listener for the event in its storage array. 26 | * 27 | * @param {Function[]} listeners Array of listeners to search through. 28 | * @param {Function} listener Method to look for. 29 | * @return {Number} Index of the specified listener, -1 if not found 30 | * @api private 31 | */ 32 | function indexOfListener(listeners, listener) { 33 | var i = listeners.length; 34 | while (i--) { 35 | if (listeners[i].listener === listener) { 36 | return i; 37 | } 38 | } 39 | 40 | return -1; 41 | } 42 | 43 | /** 44 | * Alias a method while keeping the context correct, to allow for overwriting of target method. 45 | * 46 | * @param {String} name The name of the target method. 47 | * @return {Function} The aliased method 48 | * @api private 49 | */ 50 | function alias(name) { 51 | return function aliasClosure() { 52 | return this[name].apply(this, arguments); 53 | }; 54 | } 55 | 56 | /** 57 | * Returns the listener array for the specified event. 58 | * Will initialise the event object and listener arrays if required. 59 | * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them. 60 | * Each property in the object response is an array of listener functions. 61 | * 62 | * @param {String|RegExp} evt Name of the event to return the listeners from. 63 | * @return {Function[]|Object} All listener functions for the event. 64 | */ 65 | proto.getListeners = function getListeners(evt) { 66 | var events = this._getEvents(); 67 | var response; 68 | var key; 69 | 70 | // Return a concatenated array of all matching events if 71 | // the selector is a regular expression. 72 | if (evt instanceof RegExp) { 73 | response = {}; 74 | for (key in events) { 75 | if (events.hasOwnProperty(key) && evt.test(key)) { 76 | response[key] = events[key]; 77 | } 78 | } 79 | } 80 | else { 81 | response = events[evt] || (events[evt] = []); 82 | } 83 | 84 | return response; 85 | }; 86 | 87 | /** 88 | * Takes a list of listener objects and flattens it into a list of listener functions. 89 | * 90 | * @param {Object[]} listeners Raw listener objects. 91 | * @return {Function[]} Just the listener functions. 92 | */ 93 | proto.flattenListeners = function flattenListeners(listeners) { 94 | var flatListeners = []; 95 | var i; 96 | 97 | for (i = 0; i < listeners.length; i += 1) { 98 | flatListeners.push(listeners[i].listener); 99 | } 100 | 101 | return flatListeners; 102 | }; 103 | 104 | /** 105 | * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful. 106 | * 107 | * @param {String|RegExp} evt Name of the event to return the listeners from. 108 | * @return {Object} All listener functions for an event in an object. 109 | */ 110 | proto.getListenersAsObject = function getListenersAsObject(evt) { 111 | var listeners = this.getListeners(evt); 112 | var response; 113 | 114 | if (listeners instanceof Array) { 115 | response = {}; 116 | response[evt] = listeners; 117 | } 118 | 119 | return response || listeners; 120 | }; 121 | 122 | /** 123 | * Adds a listener function to the specified event. 124 | * The listener will not be added if it is a duplicate. 125 | * If the listener returns true then it will be removed after it is called. 126 | * If you pass a regular expression as the event name then the listener will be added to all events that match it. 127 | * 128 | * @param {String|RegExp} evt Name of the event to attach the listener to. 129 | * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 130 | * @return {Object} Current instance of EventEmitter for chaining. 131 | */ 132 | proto.addListener = function addListener(evt, listener) { 133 | var listeners = this.getListenersAsObject(evt); 134 | var listenerIsWrapped = typeof listener === 'object'; 135 | var key; 136 | 137 | for (key in listeners) { 138 | if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) { 139 | listeners[key].push(listenerIsWrapped ? listener : { 140 | listener: listener, 141 | once: false 142 | }); 143 | } 144 | } 145 | 146 | return this; 147 | }; 148 | 149 | /** 150 | * Alias of addListener 151 | */ 152 | proto.on = alias('addListener'); 153 | 154 | /** 155 | * Semi-alias of addListener. It will add a listener that will be 156 | * automatically removed after its first execution. 157 | * 158 | * @param {String|RegExp} evt Name of the event to attach the listener to. 159 | * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling. 160 | * @return {Object} Current instance of EventEmitter for chaining. 161 | */ 162 | proto.addOnceListener = function addOnceListener(evt, listener) { 163 | return this.addListener(evt, { 164 | listener: listener, 165 | once: true 166 | }); 167 | }; 168 | 169 | /** 170 | * Alias of addOnceListener. 171 | */ 172 | proto.once = alias('addOnceListener'); 173 | 174 | /** 175 | * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad. 176 | * You need to tell it what event names should be matched by a regex. 177 | * 178 | * @param {String} evt Name of the event to create. 179 | * @return {Object} Current instance of EventEmitter for chaining. 180 | */ 181 | proto.defineEvent = function defineEvent(evt) { 182 | this.getListeners(evt); 183 | return this; 184 | }; 185 | 186 | /** 187 | * Uses defineEvent to define multiple events. 188 | * 189 | * @param {String[]} evts An array of event names to define. 190 | * @return {Object} Current instance of EventEmitter for chaining. 191 | */ 192 | proto.defineEvents = function defineEvents(evts) { 193 | for (var i = 0; i < evts.length; i += 1) { 194 | this.defineEvent(evts[i]); 195 | } 196 | return this; 197 | }; 198 | 199 | /** 200 | * Removes a listener function from the specified event. 201 | * When passed a regular expression as the event name, it will remove the listener from all events that match it. 202 | * 203 | * @param {String|RegExp} evt Name of the event to remove the listener from. 204 | * @param {Function} listener Method to remove from the event. 205 | * @return {Object} Current instance of EventEmitter for chaining. 206 | */ 207 | proto.removeListener = function removeListener(evt, listener) { 208 | var listeners = this.getListenersAsObject(evt); 209 | var index; 210 | var key; 211 | 212 | for (key in listeners) { 213 | if (listeners.hasOwnProperty(key)) { 214 | index = indexOfListener(listeners[key], listener); 215 | 216 | if (index !== -1) { 217 | listeners[key].splice(index, 1); 218 | } 219 | } 220 | } 221 | 222 | return this; 223 | }; 224 | 225 | /** 226 | * Alias of removeListener 227 | */ 228 | proto.off = alias('removeListener'); 229 | 230 | /** 231 | * Adds listeners in bulk using the manipulateListeners method. 232 | * If you pass an object as the second argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added. 233 | * You can also pass it a regular expression to add the array of listeners to all events that match it. 234 | * Yeah, this function does quite a bit. That's probably a bad thing. 235 | * 236 | * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once. 237 | * @param {Function[]} [listeners] An optional array of listener functions to add. 238 | * @return {Object} Current instance of EventEmitter for chaining. 239 | */ 240 | proto.addListeners = function addListeners(evt, listeners) { 241 | // Pass through to manipulateListeners 242 | return this.manipulateListeners(false, evt, listeners); 243 | }; 244 | 245 | /** 246 | * Removes listeners in bulk using the manipulateListeners method. 247 | * If you pass an object as the second argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 248 | * You can also pass it an event name and an array of listeners to be removed. 249 | * You can also pass it a regular expression to remove the listeners from all events that match it. 250 | * 251 | * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once. 252 | * @param {Function[]} [listeners] An optional array of listener functions to remove. 253 | * @return {Object} Current instance of EventEmitter for chaining. 254 | */ 255 | proto.removeListeners = function removeListeners(evt, listeners) { 256 | // Pass through to manipulateListeners 257 | return this.manipulateListeners(true, evt, listeners); 258 | }; 259 | 260 | /** 261 | * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level. 262 | * The first argument will determine if the listeners are removed (true) or added (false). 263 | * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. 264 | * You can also pass it an event name and an array of listeners to be added/removed. 265 | * You can also pass it a regular expression to manipulate the listeners of all events that match it. 266 | * 267 | * @param {Boolean} remove True if you want to remove listeners, false if you want to add. 268 | * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once. 269 | * @param {Function[]} [listeners] An optional array of listener functions to add/remove. 270 | * @return {Object} Current instance of EventEmitter for chaining. 271 | */ 272 | proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) { 273 | var i; 274 | var value; 275 | var single = remove ? this.removeListener : this.addListener; 276 | var multiple = remove ? this.removeListeners : this.addListeners; 277 | 278 | // If evt is an object then pass each of its properties to this method 279 | if (typeof evt === 'object' && !(evt instanceof RegExp)) { 280 | for (i in evt) { 281 | if (evt.hasOwnProperty(i) && (value = evt[i])) { 282 | // Pass the single listener straight through to the singular method 283 | if (typeof value === 'function') { 284 | single.call(this, i, value); 285 | } 286 | else { 287 | // Otherwise pass back to the multiple function 288 | multiple.call(this, i, value); 289 | } 290 | } 291 | } 292 | } 293 | else { 294 | // So evt must be a string 295 | // And listeners must be an array of listeners 296 | // Loop over it and pass each one to the multiple method 297 | i = listeners.length; 298 | while (i--) { 299 | single.call(this, evt, listeners[i]); 300 | } 301 | } 302 | 303 | return this; 304 | }; 305 | 306 | /** 307 | * Removes all listeners from a specified event. 308 | * If you do not specify an event then all listeners will be removed. 309 | * That means every event will be emptied. 310 | * You can also pass a regex to remove all events that match it. 311 | * 312 | * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed. 313 | * @return {Object} Current instance of EventEmitter for chaining. 314 | */ 315 | proto.removeEvent = function removeEvent(evt) { 316 | var type = typeof evt; 317 | var events = this._getEvents(); 318 | var key; 319 | 320 | // Remove different things depending on the state of evt 321 | if (type === 'string') { 322 | // Remove all listeners for the specified event 323 | delete events[evt]; 324 | } 325 | else if (evt instanceof RegExp) { 326 | // Remove all events matching the regex. 327 | for (key in events) { 328 | if (events.hasOwnProperty(key) && evt.test(key)) { 329 | delete events[key]; 330 | } 331 | } 332 | } 333 | else { 334 | // Remove all listeners in all events 335 | delete this._events; 336 | } 337 | 338 | return this; 339 | }; 340 | 341 | /** 342 | * Alias of removeEvent. 343 | * 344 | * Added to mirror the node API. 345 | */ 346 | proto.removeAllListeners = alias('removeEvent'); 347 | 348 | /** 349 | * Emits an event of your choice. 350 | * When emitted, every listener attached to that event will be executed. 351 | * If you pass the optional argument array then those arguments will be passed to every listener upon execution. 352 | * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately. 353 | * So they will not arrive within the array on the other side, they will be separate. 354 | * You can also pass a regular expression to emit to all events that match it. 355 | * 356 | * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 357 | * @param {Array} [args] Optional array of arguments to be passed to each listener. 358 | * @return {Object} Current instance of EventEmitter for chaining. 359 | */ 360 | proto.emitEvent = function emitEvent(evt, args) { 361 | var listeners = this.getListenersAsObject(evt); 362 | var listener; 363 | var i; 364 | var key; 365 | var response; 366 | 367 | for (key in listeners) { 368 | if (listeners.hasOwnProperty(key)) { 369 | i = listeners[key].length; 370 | 371 | while (i--) { 372 | // If the listener returns true then it shall be removed from the event 373 | // The function is executed either with a basic call or an apply if there is an args array 374 | listener = listeners[key][i]; 375 | 376 | if (listener.once === true) { 377 | this.removeListener(evt, listener.listener); 378 | } 379 | 380 | response = listener.listener.apply(this, args || []); 381 | 382 | if (response === this._getOnceReturnValue()) { 383 | this.removeListener(evt, listener.listener); 384 | } 385 | } 386 | } 387 | } 388 | 389 | return this; 390 | }; 391 | 392 | /** 393 | * Alias of emitEvent 394 | */ 395 | proto.trigger = alias('emitEvent'); 396 | 397 | /** 398 | * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on. 399 | * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it. 400 | * 401 | * @param {String|RegExp} evt Name of the event to emit and execute listeners for. 402 | * @param {...*} Optional additional arguments to be passed to each listener. 403 | * @return {Object} Current instance of EventEmitter for chaining. 404 | */ 405 | proto.emit = function emit(evt) { 406 | var args = Array.prototype.slice.call(arguments, 1); 407 | return this.emitEvent(evt, args); 408 | }; 409 | 410 | /** 411 | * Sets the current value to check against when executing listeners. If a 412 | * listeners return value matches the one set here then it will be removed 413 | * after execution. This value defaults to true. 414 | * 415 | * @param {*} value The new value to check for when executing listeners. 416 | * @return {Object} Current instance of EventEmitter for chaining. 417 | */ 418 | proto.setOnceReturnValue = function setOnceReturnValue(value) { 419 | this._onceReturnValue = value; 420 | return this; 421 | }; 422 | 423 | /** 424 | * Fetches the current value to check against when executing listeners. If 425 | * the listeners return value matches this one then it should be removed 426 | * automatically. It will return true by default. 427 | * 428 | * @return {*|Boolean} The current value to check for or the default, true. 429 | * @api private 430 | */ 431 | proto._getOnceReturnValue = function _getOnceReturnValue() { 432 | if (this.hasOwnProperty('_onceReturnValue')) { 433 | return this._onceReturnValue; 434 | } 435 | else { 436 | return true; 437 | } 438 | }; 439 | 440 | /** 441 | * Fetches the events object and creates one if required. 442 | * 443 | * @return {Object} The events storage object. 444 | * @api private 445 | */ 446 | proto._getEvents = function _getEvents() { 447 | return this._events || (this._events = {}); 448 | }; 449 | 450 | /** 451 | * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version. 452 | * 453 | * @return {Function} Non conflicting EventEmitter class. 454 | */ 455 | EventEmitter.noConflict = function noConflict() { 456 | exports.EventEmitter = originalGlobalValue; 457 | return EventEmitter; 458 | }; 459 | 460 | // Expose the class either via AMD, CommonJS or the global object 461 | if (typeof define === 'function' && define.amd) { 462 | define(function () { 463 | return EventEmitter; 464 | }); 465 | } 466 | else if (typeof module === 'object' && module.exports){ 467 | module.exports = EventEmitter; 468 | } 469 | else { 470 | exports.EventEmitter = EventEmitter; 471 | } 472 | }.call(this)); 473 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/lib/fetch.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | if (self.fetch) { 5 | return 6 | } 7 | 8 | function normalizeName(name) { 9 | if (typeof name !== 'string') { 10 | name = name.toString(); 11 | } 12 | if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { 13 | throw new TypeError('Invalid character in header field name') 14 | } 15 | return name.toLowerCase() 16 | } 17 | 18 | function normalizeValue(value) { 19 | if (typeof value !== 'string') { 20 | value = value.toString(); 21 | } 22 | return value 23 | } 24 | 25 | function Headers(headers) { 26 | this.map = {} 27 | 28 | if (headers instanceof Headers) { 29 | headers.forEach(function(value, name) { 30 | this.append(name, value) 31 | }, this) 32 | 33 | } else if (headers) { 34 | Object.getOwnPropertyNames(headers).forEach(function(name) { 35 | this.append(name, headers[name]) 36 | }, this) 37 | } 38 | } 39 | 40 | Headers.prototype.append = function(name, value) { 41 | name = normalizeName(name) 42 | value = normalizeValue(value) 43 | var list = this.map[name] 44 | if (!list) { 45 | list = [] 46 | this.map[name] = list 47 | } 48 | list.push(value) 49 | } 50 | 51 | Headers.prototype['delete'] = function(name) { 52 | delete this.map[normalizeName(name)] 53 | } 54 | 55 | Headers.prototype.get = function(name) { 56 | var values = this.map[normalizeName(name)] 57 | return values ? values[0] : null 58 | } 59 | 60 | Headers.prototype.getAll = function(name) { 61 | return this.map[normalizeName(name)] || [] 62 | } 63 | 64 | Headers.prototype.has = function(name) { 65 | return this.map.hasOwnProperty(normalizeName(name)) 66 | } 67 | 68 | Headers.prototype.set = function(name, value) { 69 | this.map[normalizeName(name)] = [normalizeValue(value)] 70 | } 71 | 72 | Headers.prototype.forEach = function(callback, thisArg) { 73 | Object.getOwnPropertyNames(this.map).forEach(function(name) { 74 | this.map[name].forEach(function(value) { 75 | callback.call(thisArg, value, name, this) 76 | }, this) 77 | }, this) 78 | } 79 | 80 | function consumed(body) { 81 | if (body.bodyUsed) { 82 | return Promise.reject(new TypeError('Already read')) 83 | } 84 | body.bodyUsed = true 85 | } 86 | 87 | function fileReaderReady(reader) { 88 | return new Promise(function(resolve, reject) { 89 | reader.onload = function() { 90 | resolve(reader.result) 91 | } 92 | reader.onerror = function() { 93 | reject(reader.error) 94 | } 95 | }) 96 | } 97 | 98 | function readBlobAsArrayBuffer(blob) { 99 | var reader = new FileReader() 100 | reader.readAsArrayBuffer(blob) 101 | return fileReaderReady(reader) 102 | } 103 | 104 | function readBlobAsText(blob) { 105 | var reader = new FileReader() 106 | reader.readAsText(blob) 107 | return fileReaderReady(reader) 108 | } 109 | 110 | var support = { 111 | blob: 'FileReader' in self && 'Blob' in self && (function() { 112 | try { 113 | new Blob(); 114 | return true 115 | } catch(e) { 116 | return false 117 | } 118 | })(), 119 | formData: 'FormData' in self 120 | } 121 | 122 | function Body() { 123 | this.bodyUsed = false 124 | 125 | 126 | this._initBody = function(body) { 127 | this._bodyInit = body 128 | if (typeof body === 'string') { 129 | this._bodyText = body 130 | } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { 131 | this._bodyBlob = body 132 | } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { 133 | this._bodyFormData = body 134 | } else if (!body) { 135 | this._bodyText = '' 136 | } else { 137 | throw new Error('unsupported BodyInit type') 138 | } 139 | } 140 | 141 | if (support.blob) { 142 | this.blob = function() { 143 | var rejected = consumed(this) 144 | if (rejected) { 145 | return rejected 146 | } 147 | 148 | if (this._bodyBlob) { 149 | return Promise.resolve(this._bodyBlob) 150 | } else if (this._bodyFormData) { 151 | throw new Error('could not read FormData body as blob') 152 | } else { 153 | return Promise.resolve(new Blob([this._bodyText])) 154 | } 155 | } 156 | 157 | this.arrayBuffer = function() { 158 | return this.blob().then(readBlobAsArrayBuffer) 159 | } 160 | 161 | this.text = function() { 162 | var rejected = consumed(this) 163 | if (rejected) { 164 | return rejected 165 | } 166 | 167 | if (this._bodyBlob) { 168 | return readBlobAsText(this._bodyBlob) 169 | } else if (this._bodyFormData) { 170 | throw new Error('could not read FormData body as text') 171 | } else { 172 | return Promise.resolve(this._bodyText) 173 | } 174 | } 175 | } else { 176 | this.text = function() { 177 | var rejected = consumed(this) 178 | return rejected ? rejected : Promise.resolve(this._bodyText) 179 | } 180 | } 181 | 182 | if (support.formData) { 183 | this.formData = function() { 184 | return this.text().then(decode) 185 | } 186 | } 187 | 188 | this.json = function() { 189 | return this.text().then(JSON.parse) 190 | } 191 | 192 | return this 193 | } 194 | 195 | // HTTP methods whose capitalization should be normalized 196 | var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] 197 | 198 | function normalizeMethod(method) { 199 | var upcased = method.toUpperCase() 200 | return (methods.indexOf(upcased) > -1) ? upcased : method 201 | } 202 | 203 | function Request(url, options) { 204 | options = options || {} 205 | this.url = url 206 | 207 | this.credentials = options.credentials || 'omit' 208 | this.headers = new Headers(options.headers) 209 | this.method = normalizeMethod(options.method || 'GET') 210 | this.mode = options.mode || null 211 | this.referrer = null 212 | 213 | if ((this.method === 'GET' || this.method === 'HEAD') && options.body) { 214 | throw new TypeError('Body not allowed for GET or HEAD requests') 215 | } 216 | this._initBody(options.body) 217 | } 218 | 219 | function decode(body) { 220 | var form = new FormData() 221 | body.trim().split('&').forEach(function(bytes) { 222 | if (bytes) { 223 | var split = bytes.split('=') 224 | var name = split.shift().replace(/\+/g, ' ') 225 | var value = split.join('=').replace(/\+/g, ' ') 226 | form.append(decodeURIComponent(name), decodeURIComponent(value)) 227 | } 228 | }) 229 | return form 230 | } 231 | 232 | function headers(xhr) { 233 | var head = new Headers() 234 | var pairs = xhr.getAllResponseHeaders().trim().split('\n') 235 | pairs.forEach(function(header) { 236 | var split = header.trim().split(':') 237 | var key = split.shift().trim() 238 | var value = split.join(':').trim() 239 | head.append(key, value) 240 | }) 241 | return head 242 | } 243 | 244 | Body.call(Request.prototype) 245 | 246 | function Response(bodyInit, options) { 247 | if (!options) { 248 | options = {} 249 | } 250 | 251 | this._initBody(bodyInit) 252 | this.type = 'default' 253 | this.url = null 254 | this.status = options.status 255 | this.ok = this.status >= 200 && this.status < 300 256 | this.statusText = options.statusText 257 | this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers) 258 | this.url = options.url || '' 259 | } 260 | 261 | Body.call(Response.prototype) 262 | 263 | self.Headers = Headers; 264 | self.Request = Request; 265 | self.Response = Response; 266 | 267 | self.fetch = function(input, init) { 268 | // TODO: Request constructor should accept input, init 269 | var request 270 | if (Request.prototype.isPrototypeOf(input) && !init) { 271 | request = input 272 | } else { 273 | request = new Request(input, init) 274 | } 275 | 276 | return new Promise(function(resolve, reject) { 277 | var xhr = new XMLHttpRequest() 278 | 279 | function responseURL() { 280 | if ('responseURL' in xhr) { 281 | return xhr.responseURL 282 | } 283 | 284 | // Avoid security warnings on getResponseHeader when not allowed by CORS 285 | if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) { 286 | return xhr.getResponseHeader('X-Request-URL') 287 | } 288 | 289 | return; 290 | } 291 | 292 | xhr.onload = function() { 293 | var status = (xhr.status === 1223) ? 204 : xhr.status 294 | if (status < 100 || status > 599) { 295 | reject(new TypeError('Network request failed')) 296 | return 297 | } 298 | var options = { 299 | status: status, 300 | statusText: xhr.statusText, 301 | headers: headers(xhr), 302 | url: responseURL() 303 | } 304 | var body = 'response' in xhr ? xhr.response : xhr.responseText; 305 | resolve(new Response(body, options)) 306 | } 307 | 308 | xhr.onerror = function() { 309 | reject(new TypeError('Network request failed')) 310 | } 311 | 312 | xhr.open(request.method, request.url, true) 313 | 314 | if (request.credentials === 'include') { 315 | xhr.withCredentials = true 316 | } 317 | 318 | if ('responseType' in xhr && support.blob) { 319 | xhr.responseType = 'blob' 320 | } 321 | 322 | request.headers.forEach(function(value, name) { 323 | xhr.setRequestHeader(name, value) 324 | }) 325 | 326 | xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) 327 | }) 328 | } 329 | self.fetch.polyfill = true 330 | })(); 331 | -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/lib/flux.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Flux = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o} ids 163 | */ 164 | Dispatcher.prototype.waitFor=function(ids) { 165 | invariant( 166 | this._isDispatching, 167 | 'Dispatcher.waitFor(...): Must be invoked while dispatching.' 168 | ); 169 | for (var ii = 0; ii < ids.length; ii++) { 170 | var id = ids[ii]; 171 | if (this._isPending[id]) { 172 | invariant( 173 | this._isHandled[id], 174 | 'Dispatcher.waitFor(...): Circular dependency detected while ' + 175 | 'waiting for `%s`.', 176 | id 177 | ); 178 | continue; 179 | } 180 | invariant( 181 | this._callbacks[id], 182 | 'Dispatcher.waitFor(...): `%s` does not map to a registered callback.', 183 | id 184 | ); 185 | this._invokeCallback(id); 186 | } 187 | }; 188 | 189 | /** 190 | * Dispatches a payload to all registered callbacks. 191 | * 192 | * @param {object} payload 193 | */ 194 | Dispatcher.prototype.dispatch=function(payload) { 195 | invariant( 196 | !this._isDispatching, 197 | 'Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.' 198 | ); 199 | this._startDispatching(payload); 200 | try { 201 | for (var id in this._callbacks) { 202 | if (this._isPending[id]) { 203 | continue; 204 | } 205 | this._invokeCallback(id); 206 | } 207 | } finally { 208 | this._stopDispatching(); 209 | } 210 | }; 211 | 212 | /** 213 | * Is this Dispatcher currently dispatching. 214 | * 215 | * @return {boolean} 216 | */ 217 | Dispatcher.prototype.isDispatching=function() { 218 | return this._isDispatching; 219 | }; 220 | 221 | /** 222 | * Call the callback stored with the given id. Also do some internal 223 | * bookkeeping. 224 | * 225 | * @param {string} id 226 | * @internal 227 | */ 228 | Dispatcher.prototype._invokeCallback=function(id) { 229 | this._isPending[id] = true; 230 | this._callbacks[id](this._pendingPayload); 231 | this._isHandled[id] = true; 232 | }; 233 | 234 | /** 235 | * Set up bookkeeping needed when dispatching. 236 | * 237 | * @param {object} payload 238 | * @internal 239 | */ 240 | Dispatcher.prototype._startDispatching=function(payload) { 241 | for (var id in this._callbacks) { 242 | this._isPending[id] = false; 243 | this._isHandled[id] = false; 244 | } 245 | this._pendingPayload = payload; 246 | this._isDispatching = true; 247 | }; 248 | 249 | /** 250 | * Clear bookkeeping used for dispatching. 251 | * 252 | * @internal 253 | */ 254 | Dispatcher.prototype._stopDispatching=function() { 255 | this._pendingPayload = null; 256 | this._isDispatching = false; 257 | }; 258 | 259 | 260 | module.exports = Dispatcher; 261 | 262 | },{"./invariant":3}],3:[function(require,module,exports){ 263 | /** 264 | * Copyright (c) 2014-2015, Facebook, Inc. 265 | * All rights reserved. 266 | * 267 | * This source code is licensed under the BSD-style license found in the 268 | * LICENSE file in the root directory of this source tree. An additional grant 269 | * of patent rights can be found in the PATENTS file in the same directory. 270 | * 271 | * @providesModule invariant 272 | */ 273 | 274 | "use strict"; 275 | 276 | /** 277 | * Use invariant() to assert state which your program assumes to be true. 278 | * 279 | * Provide sprintf-style format (only %s is supported) and arguments 280 | * to provide information about what broke and what you were 281 | * expecting. 282 | * 283 | * The invariant message will be stripped in production, but the invariant 284 | * will remain to ensure logic does not differ in production. 285 | */ 286 | 287 | var invariant = function(condition, format, a, b, c, d, e, f) { 288 | if (false) { 289 | if (format === undefined) { 290 | throw new Error('invariant requires an error message argument'); 291 | } 292 | } 293 | 294 | if (!condition) { 295 | var error; 296 | if (format === undefined) { 297 | error = new Error( 298 | 'Minified exception occurred; use the non-minified dev environment ' + 299 | 'for the full error message and additional helpful warnings.' 300 | ); 301 | } else { 302 | var args = [a, b, c, d, e, f]; 303 | var argIndex = 0; 304 | error = new Error( 305 | 'Invariant Violation: ' + 306 | format.replace(/%s/g, function() { return args[argIndex++]; }) 307 | ); 308 | } 309 | 310 | error.framesToPop = 1; // we don't care about invariant's own frame 311 | throw error; 312 | } 313 | }; 314 | 315 | module.exports = invariant; 316 | 317 | },{}]},{},[1])(1) 318 | }); -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/lib/promise.js: -------------------------------------------------------------------------------- 1 | (function e(t, n, r) { 2 | function s(o, u) { 3 | if (!n[o]) { 4 | if (!t[o]) { 5 | var a = typeof require == "function" && require; 6 | if (!u && a) return a(o, !0); 7 | if (i) return i(o, !0); 8 | var f = new Error("Cannot find module '" + o + "'"); 9 | throw f.code = "MODULE_NOT_FOUND", f; 10 | } 11 | var l = n[o] = { 12 | exports: {} 13 | }; 14 | t[o][0].call(l.exports, function(e) { 15 | var n = t[o][1][e]; 16 | return s(n ? n : e); 17 | }, l, l.exports, e, t, n, r); 18 | } 19 | return n[o].exports; 20 | } 21 | var i = typeof require == "function" && require; 22 | for (var o = 0; o < r.length; o++) s(r[o]); 23 | return s; 24 | })({ 25 | 1: [ function(require, module, exports) { 26 | var process = module.exports = {}; 27 | process.nextTick = function() { 28 | var canSetImmediate = typeof window !== "undefined" && window.setImmediate; 29 | var canPost = typeof window !== "undefined" && window.postMessage && window.addEventListener; 30 | if (canSetImmediate) { 31 | return function(f) { 32 | return window.setImmediate(f); 33 | }; 34 | } 35 | if (canPost) { 36 | var queue = []; 37 | window.addEventListener("message", function(ev) { 38 | var source = ev.source; 39 | if ((source === window || source === null) && ev.data === "process-tick") { 40 | ev.stopPropagation(); 41 | if (queue.length > 0) { 42 | var fn = queue.shift(); 43 | fn(); 44 | } 45 | } 46 | }, true); 47 | return function nextTick(fn) { 48 | queue.push(fn); 49 | window.postMessage("process-tick", "*"); 50 | }; 51 | } 52 | return function nextTick(fn) { 53 | setTimeout(fn, 0); 54 | }; 55 | }(); 56 | process.title = "browser"; 57 | process.browser = true; 58 | process.env = {}; 59 | process.argv = []; 60 | function noop() {} 61 | process.on = noop; 62 | process.addListener = noop; 63 | process.once = noop; 64 | process.off = noop; 65 | process.removeListener = noop; 66 | process.removeAllListeners = noop; 67 | process.emit = noop; 68 | process.binding = function(name) { 69 | throw new Error("process.binding is not supported"); 70 | }; 71 | process.cwd = function() { 72 | return "/"; 73 | }; 74 | process.chdir = function(dir) { 75 | throw new Error("process.chdir is not supported"); 76 | }; 77 | }, {} ], 78 | 2: [ function(require, module, exports) { 79 | "use strict"; 80 | var asap = require("asap"); 81 | module.exports = Promise; 82 | function Promise(fn) { 83 | if (typeof this !== "object") throw new TypeError("Promises must be constructed via new"); 84 | if (typeof fn !== "function") throw new TypeError("not a function"); 85 | var state = null; 86 | var value = null; 87 | var deferreds = []; 88 | var self = this; 89 | this.then = function(onFulfilled, onRejected) { 90 | return new self.constructor(function(resolve, reject) { 91 | handle(new Handler(onFulfilled, onRejected, resolve, reject)); 92 | }); 93 | }; 94 | function handle(deferred) { 95 | if (state === null) { 96 | deferreds.push(deferred); 97 | return; 98 | } 99 | asap(function() { 100 | var cb = state ? deferred.onFulfilled : deferred.onRejected; 101 | if (cb === null) { 102 | (state ? deferred.resolve : deferred.reject)(value); 103 | return; 104 | } 105 | var ret; 106 | try { 107 | ret = cb(value); 108 | } catch (e) { 109 | deferred.reject(e); 110 | return; 111 | } 112 | deferred.resolve(ret); 113 | }); 114 | } 115 | function resolve(newValue) { 116 | try { 117 | if (newValue === self) throw new TypeError("A promise cannot be resolved with itself."); 118 | if (newValue && (typeof newValue === "object" || typeof newValue === "function")) { 119 | var then = newValue.then; 120 | if (typeof then === "function") { 121 | doResolve(then.bind(newValue), resolve, reject); 122 | return; 123 | } 124 | } 125 | state = true; 126 | value = newValue; 127 | finale(); 128 | } catch (e) { 129 | reject(e); 130 | } 131 | } 132 | function reject(newValue) { 133 | state = false; 134 | value = newValue; 135 | finale(); 136 | } 137 | function finale() { 138 | for (var i = 0, len = deferreds.length; i < len; i++) handle(deferreds[i]); 139 | deferreds = null; 140 | } 141 | doResolve(fn, resolve, reject); 142 | } 143 | function Handler(onFulfilled, onRejected, resolve, reject) { 144 | this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled : null; 145 | this.onRejected = typeof onRejected === "function" ? onRejected : null; 146 | this.resolve = resolve; 147 | this.reject = reject; 148 | } 149 | function doResolve(fn, onFulfilled, onRejected) { 150 | var done = false; 151 | try { 152 | fn(function(value) { 153 | if (done) return; 154 | done = true; 155 | onFulfilled(value); 156 | }, function(reason) { 157 | if (done) return; 158 | done = true; 159 | onRejected(reason); 160 | }); 161 | } catch (ex) { 162 | if (done) return; 163 | done = true; 164 | onRejected(ex); 165 | } 166 | } 167 | }, { 168 | asap: 4 169 | } ], 170 | 3: [ function(require, module, exports) { 171 | "use strict"; 172 | var Promise = require("./core.js"); 173 | var asap = require("asap"); 174 | module.exports = Promise; 175 | function ValuePromise(value) { 176 | this.then = function(onFulfilled) { 177 | if (typeof onFulfilled !== "function") return this; 178 | return new Promise(function(resolve, reject) { 179 | asap(function() { 180 | try { 181 | resolve(onFulfilled(value)); 182 | } catch (ex) { 183 | reject(ex); 184 | } 185 | }); 186 | }); 187 | }; 188 | } 189 | ValuePromise.prototype = Promise.prototype; 190 | var TRUE = new ValuePromise(true); 191 | var FALSE = new ValuePromise(false); 192 | var NULL = new ValuePromise(null); 193 | var UNDEFINED = new ValuePromise(undefined); 194 | var ZERO = new ValuePromise(0); 195 | var EMPTYSTRING = new ValuePromise(""); 196 | Promise.resolve = function(value) { 197 | if (value instanceof Promise) return value; 198 | if (value === null) return NULL; 199 | if (value === undefined) return UNDEFINED; 200 | if (value === true) return TRUE; 201 | if (value === false) return FALSE; 202 | if (value === 0) return ZERO; 203 | if (value === "") return EMPTYSTRING; 204 | if (typeof value === "object" || typeof value === "function") { 205 | try { 206 | var then = value.then; 207 | if (typeof then === "function") { 208 | return new Promise(then.bind(value)); 209 | } 210 | } catch (ex) { 211 | return new Promise(function(resolve, reject) { 212 | reject(ex); 213 | }); 214 | } 215 | } 216 | return new ValuePromise(value); 217 | }; 218 | Promise.all = function(arr) { 219 | var args = Array.prototype.slice.call(arr); 220 | return new Promise(function(resolve, reject) { 221 | if (args.length === 0) return resolve([]); 222 | var remaining = args.length; 223 | function res(i, val) { 224 | try { 225 | if (val && (typeof val === "object" || typeof val === "function")) { 226 | var then = val.then; 227 | if (typeof then === "function") { 228 | then.call(val, function(val) { 229 | res(i, val); 230 | }, reject); 231 | return; 232 | } 233 | } 234 | args[i] = val; 235 | if (--remaining === 0) { 236 | resolve(args); 237 | } 238 | } catch (ex) { 239 | reject(ex); 240 | } 241 | } 242 | for (var i = 0; i < args.length; i++) { 243 | res(i, args[i]); 244 | } 245 | }); 246 | }; 247 | Promise.reject = function(value) { 248 | return new Promise(function(resolve, reject) { 249 | reject(value); 250 | }); 251 | }; 252 | Promise.race = function(values) { 253 | return new Promise(function(resolve, reject) { 254 | values.forEach(function(value) { 255 | Promise.resolve(value).then(resolve, reject); 256 | }); 257 | }); 258 | }; 259 | Promise.prototype["catch"] = function(onRejected) { 260 | return this.then(null, onRejected); 261 | }; 262 | }, { 263 | "./core.js": 2, 264 | asap: 4 265 | } ], 266 | 4: [ function(require, module, exports) { 267 | (function(process) { 268 | var head = { 269 | task: void 0, 270 | next: null 271 | }; 272 | var tail = head; 273 | var flushing = false; 274 | var requestFlush = void 0; 275 | var isNodeJS = false; 276 | function flush() { 277 | while (head.next) { 278 | head = head.next; 279 | var task = head.task; 280 | head.task = void 0; 281 | var domain = head.domain; 282 | if (domain) { 283 | head.domain = void 0; 284 | domain.enter(); 285 | } 286 | try { 287 | task(); 288 | } catch (e) { 289 | if (isNodeJS) { 290 | if (domain) { 291 | domain.exit(); 292 | } 293 | setTimeout(flush, 0); 294 | if (domain) { 295 | domain.enter(); 296 | } 297 | throw e; 298 | } else { 299 | setTimeout(function() { 300 | throw e; 301 | }, 0); 302 | } 303 | } 304 | if (domain) { 305 | domain.exit(); 306 | } 307 | } 308 | flushing = false; 309 | } 310 | if (typeof process !== "undefined" && process.nextTick) { 311 | isNodeJS = true; 312 | requestFlush = function() { 313 | process.nextTick(flush); 314 | }; 315 | } else if (typeof setImmediate === "function") { 316 | if (typeof window !== "undefined") { 317 | requestFlush = setImmediate.bind(window, flush); 318 | } else { 319 | requestFlush = function() { 320 | setImmediate(flush); 321 | }; 322 | } 323 | } else if (typeof MessageChannel !== "undefined") { 324 | var channel = new MessageChannel(); 325 | channel.port1.onmessage = flush; 326 | requestFlush = function() { 327 | channel.port2.postMessage(0); 328 | }; 329 | } else { 330 | requestFlush = function() { 331 | setTimeout(flush, 0); 332 | }; 333 | } 334 | function asap(task) { 335 | tail = tail.next = { 336 | task: task, 337 | domain: isNodeJS && process.domain, 338 | next: null 339 | }; 340 | if (!flushing) { 341 | flushing = true; 342 | requestFlush(); 343 | } 344 | } 345 | module.exports = asap; 346 | }).call(this, require("_process")); 347 | }, { 348 | _process: 1 349 | } ], 350 | 5: [ function(require, module, exports) { 351 | if (typeof Promise.prototype.done !== "function") { 352 | Promise.prototype.done = function(onFulfilled, onRejected) { 353 | var self = arguments.length ? this.then.apply(this, arguments) : this; 354 | self.then(null, function(err) { 355 | setTimeout(function() { 356 | throw err; 357 | }, 0); 358 | }); 359 | }; 360 | } 361 | }, {} ], 362 | 6: [ function(require, module, exports) { 363 | var asap = require("asap"); 364 | if (typeof Promise === "undefined") { 365 | Promise = require("./lib/core.js"); 366 | require("./lib/es6-extensions.js"); 367 | } 368 | require("./polyfill-done.js"); 369 | }, { 370 | "./lib/core.js": 2, 371 | "./lib/es6-extensions.js": 3, 372 | "./polyfill-done.js": 5, 373 | asap: 4 374 | } ] 375 | }, {}, [ 6 ]); 376 | //# sourceMappingURL=/polyfills/promise-6.1.0.js.map -------------------------------------------------------------------------------- /flux-demo/flux-demo-static/src/js/store/flux-demo.js: -------------------------------------------------------------------------------- 1 | import dispatcher from '../dispatcher/dispatcher'; 2 | 3 | const data = { 4 | introduction: {} 5 | }; 6 | 7 | const createStore = (methods) => { 8 | let name; 9 | 10 | class Store extends EventEmitter {}; 11 | 12 | for (name in methods) { 13 | Store.prototype[name] = methods[name]; 14 | } 15 | 16 | return new Store(); 17 | }; 18 | 19 | const fluxDemoStore = createStore({ 20 | getIntroduction (name) { 21 | return data.introduction[name]; 22 | } 23 | }); 24 | 25 | fluxDemoStore.dispatchToken = dispatcher.register((action) => { 26 | switch(action.type) { 27 | case 'FETCH_INTRODUCTION': 28 | // do something 29 | break; 30 | 31 | case 'FETCH_INTRODUCTION_SUCCESS': 32 | data.introduction[action.name] = action.response.data; 33 | fluxDemoStore.emit('change'); 34 | break; 35 | 36 | case 'FETCH_INTRODUCTION_ERROR': 37 | // do something 38 | break; 39 | } 40 | }); 41 | 42 | export default fluxDemoStore; 43 | -------------------------------------------------------------------------------- /react-router-demo/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | .orig 4 | .swp 5 | src/js/bundle.js 6 | .cache/ 7 | npm-debug.log 8 | -------------------------------------------------------------------------------- /react-router-demo/README.md: -------------------------------------------------------------------------------- 1 | # React Router Demo 2 | 3 | ### 启动项目 4 | 5 | 在项目根目录中先执行 `npm install` 安装依赖,依赖安装结束后执行 `npm start` 就启动了项目,浏览器中输入 `http://127.0.0.1:3002` 即可访问。 6 | 7 | 本 Demo 在 [从 React Router 谈谈路由的那些事](http://stylechen.com/react-router.html) 有详细的讲解。 -------------------------------------------------------------------------------- /react-router-demo/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var gutil = require('gulp-util'); 3 | var babelify = require('babelify'); 4 | var browserify = require('browserify'); 5 | var watchify = require('watchify'); 6 | var cacheify = require('cacheify'); 7 | var levelup = require('levelup'); 8 | var source = require('vinyl-source-stream'); 9 | var less = require('gulp-less'); 10 | var connect = require('gulp-connect'); 11 | var LessPluginAutoPrefix = require('less-plugin-autoprefix'); 12 | var autoprefix= new LessPluginAutoPrefix({ browsers: ['last 2 versions'] }); 13 | var db = levelup('./.cache'); 14 | 15 | var srcRoot = 'src'; 16 | var jsSrcPath = './src/js/index.js'; 17 | var jsDestPath = './src/js'; 18 | 19 | var browserOpts = { 20 | entries: [jsSrcPath], 21 | debug: true, 22 | insertGlobals: true 23 | }; 24 | 25 | gulp.task('connect', function () { 26 | connect.server({ 27 | root: [srcRoot], 28 | port: 3002, 29 | livereload: true, 30 | fallback: 'src/index.html' 31 | }); 32 | }); 33 | 34 | gulp.task('watch-html', function () { 35 | gulp.watch(srcRoot + '/**/*.html', function () { 36 | return gulp.src(srcRoot + '/**/*.html') 37 | .pipe(connect.reload()); 38 | }); 39 | }); 40 | 41 | var bundle = function () { 42 | return watcher.bundle() 43 | .on('error', function (err) { 44 | console.log(err.message); 45 | console.log(err.stack); 46 | }) 47 | .pipe(source('bundle.js')) 48 | .pipe(gulp.dest(jsDestPath)) 49 | .pipe(connect.reload()); 50 | }; 51 | 52 | var babelifyCache = cacheify(babelify.configure({ 53 | presets: ["es2015", "react"] 54 | }), db); 55 | 56 | var bundler = browserify(browserOpts) 57 | .transform(babelifyCache); 58 | 59 | var watcher = watchify(bundler) 60 | .on('update', bundle) 61 | .on('log', gutil.log); 62 | 63 | gulp.task('watch-js', bundle); 64 | gulp.task('watch', ['watch-js', 'watch-html']) 65 | gulp.task('default', ['connect', 'watch']); 66 | -------------------------------------------------------------------------------- /react-router-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-router-demo", 3 | "version": "0.2.0", 4 | "description": "", 5 | "scripts": { 6 | "start": "gulp", 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "chenmnkken@gmail.com", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "babel-preset-es2015": "6.1.18", 13 | "babel-preset-react": "6.1.18", 14 | "babelify": "7.2.0", 15 | "browserify": "12.0.1", 16 | "cacheify": "0.4.1", 17 | "gulp": "3.9.0", 18 | "gulp-connect": "2.2.0", 19 | "gulp-less": "3.0.5", 20 | "gulp-util": "3.0.7", 21 | "less-plugin-autoprefix": "1.5.1", 22 | "leveldown": "1.4.2", 23 | "levelup": "1.3.0", 24 | "vinyl-source-stream": "1.1.0", 25 | "watchify": "3.6.1" 26 | }, 27 | "dependencies": { 28 | "react": "0.14.5", 29 | "react-dom": "0.14.5", 30 | "react-router": "2.0.0-rc4" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /react-router-demo/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React Router Demo 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /react-router-demo/src/js/component/about.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | class About extends React.Component { 4 | componentDidMount () { 5 | console.log('mount'); 6 | } 7 | 8 | componentWillUnmount () { 9 | console.log('un mount'); 10 | } 11 | 12 | render () { 13 | return ( 14 |

This is About page.

15 | ); 16 | } 17 | }; 18 | 19 | export default About; 20 | -------------------------------------------------------------------------------- /react-router-demo/src/js/component/app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Link} from 'react-router'; 3 | 4 | class App extends React.Component { 5 | render () { 6 | return ( 7 |
8 |

React Router Demo

9 |
10 |

11 | by stylechen.com 12 |

13 |
    14 |
  • Home
  • 15 |
  • About
  • 16 |
  • Concat
  • 17 |
  • List 001
  • 18 |
  • List 002
  • 19 |
20 | {this.props.children} 21 |
22 | ) 23 | } 24 | }; 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /react-router-demo/src/js/component/concat.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Concat = () => { 4 | return ( 5 |

This is Concat page.

6 | ); 7 | }; 8 | 9 | export default Concat; 10 | -------------------------------------------------------------------------------- /react-router-demo/src/js/component/list.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | class List extends React.Component { 4 | render () { 5 | return ( 6 |
7 |

This is List page.

8 |

The list page id is  9 | {this.props.params.id} 10 |

11 |
12 | ); 13 | } 14 | }; 15 | 16 | export default List; 17 | -------------------------------------------------------------------------------- /react-router-demo/src/js/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import App from './component/app'; 5 | import About from './component/about'; 6 | import Concat from './component/concat'; 7 | import List from './component/list'; 8 | 9 | import {Router, Route, browserHistory} from 'react-router'; 10 | 11 | const router = ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | 21 | ReactDOM.render( 22 | router, 23 | document.getElementById('root') 24 | ); 25 | --------------------------------------------------------------------------------