├── .babelrc ├── .gitattributes ├── .gitignore ├── .idea └── scopes │ └── scope_settings.xml ├── LICENSE ├── README.md ├── bower_components ├── chai │ ├── .bower.json │ ├── CONTRIBUTING.md │ ├── History.md │ ├── README.md │ ├── ReleaseNotes.md │ ├── bower.json │ ├── chai.js │ ├── component.json │ ├── karma.conf.js │ ├── karma.sauce.js │ ├── package.json │ └── sauce.browsers.js └── mocha │ ├── .bower.json │ ├── .editorconfig │ ├── .mailmap │ ├── CONTRIBUTING.md │ ├── HISTORY.md │ ├── LICENSE │ ├── README.md │ ├── bower.json │ ├── media │ └── logo.svg │ ├── mocha.css │ └── mocha.js ├── demo ├── app.css ├── demo-choose-web-framework.coffee ├── demo-controls.coffee ├── demo-counter.coffee ├── demo-debug.coffee ├── demo-each.coffee ├── demo-function-lead-item.coffee ├── demo-show-hide.coffee ├── demo-sum.coffee ├── demo-text-model.coffee ├── index-dist.html ├── index.coffee ├── index.html ├── learn.json ├── todomvc-dist.html ├── todomvc.coffee ├── todomvc.css ├── todomvc.html └── util.coffee ├── dist ├── demo.js ├── domcom.js ├── domcom.min.js ├── test.js └── todomvc.js ├── doc ├── concepts and principles.md ├── Chinese │ ├── API参考.md │ ├── 介绍和辅导教程.md │ ├── 从React到Domcom.md │ ├── 包目录结构.md │ ├── 常见问题.md │ ├── 概念和原理.md │ └── 速查表.md ├── From-react-to-domcom.md ├── api-reference.md ├── cheat-sheet.md ├── faq.md ├── introduction and tutorials.md └── package-directory.md ├── gulpfile.js ├── history.md ├── package-lock.json ├── package.json ├── scripts ├── tasks │ ├── build-tasks.coffee │ ├── clean.coffee │ ├── coffee.coffee │ ├── remove.coffee │ ├── rename.coffee │ ├── typescript.coffee │ └── webpack.coffee └── webpack-config.coffee ├── src ├── Component.coffee ├── Emitter.coffee ├── dc-directive.coffee ├── dc-error.coffee ├── dc-util.coffee ├── index.coffee └── react-proxy.coffee ├── static ├── bootstrap-3.3.4-dist │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── npm.js └── js │ └── sinon-1.15.4.js ├── test ├── draft.html ├── helper.coffee ├── index.coffee ├── mocha-runner-dist.html ├── mocha-runner.html ├── mocha-test.css ├── react-vue-components │ ├── HelloReact.coffee │ └── HelloVue.coffee ├── test-antd.coffee ├── test-directive.coffee ├── test-event.coffee ├── test-material-ui.coffee ├── test-new-dc.coffee └── test-react-proxy.coffee └── todo.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "presets": ["es2015", "react"], 4 | "plugins": [] 5 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | bower_components 4 | 5 | dev 6 | app 7 | build 8 | 9 | public 10 | 11 | .idea 12 | .tmp 13 | temp 14 | temp.* 15 | .sass-cache 16 | .DS_Store 17 | .sass-cache 18 | db 19 | 20 | .idea/**/*.xml 21 | webpack.config.js 22 | *-.js 23 | *-.coffee 24 | *.log 25 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2017 曹星明(Caoxingming, simeon.chaos@gmail.com) 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Domcom 2 | the web framework to provide dom component 3 | 4 | ## document 5 | 6 | See [doc/](https://github.com/taijiweb/domcom/tree/master/doc) for the document. Both English and Chinese document are provided. 7 | 8 | #### 中文文档: **请看 [doc/Chinese/](https://github.com/taijiweb/domcom/tree/master/doc/Chinese) 文件夹。** 9 | 10 | ## download and install 11 | 12 | npm install --save domcom 13 | 14 | useDomcom in page by script tag,add React andReactDom at first 15 | 16 | 17 | 18 | 19 | or 20 | 21 | 22 | 23 | 24 | and then add script tag for Domcom itself: 25 | 26 | 27 | 28 | 29 | or use the cdn provided by unpg or jsdelivr: 30 | 31 | 32 | https://unpkg.com/domcom/dist/domcom.js 33 | https://unpkg.com/domcom/dist/domcom.min.js 34 | https://cdn.jsdelivr.net/npm/domcom/dist/domcom.js 35 | https://cdn.jsdelivr.net/npm/domcom/dist/domcom.min.js 36 | 37 | ## Features 38 | * simple API: 39 | 40 | component = dc({data, view}); 41 | component.mount(parentNode); 42 | component.update() 43 | 44 | * use plain array tree as view language, long live js, byebye JSX 45 | 46 | * MVC pattern( data/view/Component), byebye flux/redux 47 | data is the model, Component is just the controller 48 | 49 | * render to dom by react( maybe add other proxy, e.g. Vue, in the future) 50 | 51 | ## Samples 52 | There is [some samples](https://github.com/taijiweb/domcom/tree/master/demo), and a [todoMVC implementation](https://github.com/taijiweb/domcom/tree/master/demo/coffee/todomvc.coffee). 53 | 54 | The code below give a taste of domcom: 55 | 56 | const data = { a: 1, b: 2 }; 57 | const view = data => { 58 | let props1 = { 59 | value: data.a, 60 | onChange(event) { 61 | data.a = event.target.value*1 62 | comp.update() 63 | } 64 | }; 65 | props2 = { 66 | value: data.b, 67 | onChange(event) { 68 | data.b = event.target.value*1 69 | comp.update(); 70 | }; 71 | }; 72 | return ['div', 73 | ['text', props1], 74 | ['text', props2], 75 | ['p', data.a + data.b] 76 | ]; 77 | }; 78 | const comp = dc({data, view}); 79 | comp.mount('#demo'); 80 | 81 | 82 | ## LICENSE 83 | MIT, see [LICENSE](https://github.com/taijiweb/domcom/blob/master/LICENSE) 84 | -------------------------------------------------------------------------------- /bower_components/chai/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chai", 3 | "version": "2.1.1", 4 | "description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic.", 5 | "license": "MIT", 6 | "keywords": [ 7 | "test", 8 | "assertion", 9 | "assert", 10 | "testing", 11 | "chai" 12 | ], 13 | "main": "chai.js", 14 | "ignore": [ 15 | "build", 16 | "components", 17 | "lib", 18 | "node_modules", 19 | "support", 20 | "test", 21 | "index.js", 22 | "Makefile", 23 | ".*" 24 | ], 25 | "dependencies": {}, 26 | "devDependencies": {}, 27 | "homepage": "https://github.com/chaijs/chai", 28 | "_release": "2.1.1", 29 | "_resolution": { 30 | "type": "version", 31 | "tag": "2.1.1", 32 | "commit": "d7cafca0232756f767275bb00e66930a7823b027" 33 | }, 34 | "_source": "git://github.com/chaijs/chai.git", 35 | "_target": "~2.1.1", 36 | "_originalSource": "chai", 37 | "_direct": true 38 | } -------------------------------------------------------------------------------- /bower_components/chai/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Chai Contribution Guidelines 2 | 3 | We like to encourage you to contribute to the Chai.js repository. This should be as easy as possible for you but there are a few things to consider when contributing. The following guidelines for contribution should be followed if you want to submit a pull request or open an issue. 4 | 5 | Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue or assessing patches and features. 6 | 7 | #### Table of Contents 8 | 9 | - [TLDR;](#tldr) 10 | - [Contributing](#contributing) 11 | - [Bug Reports](#bugs) 12 | - [Feature Requests](#features) 13 | - [Pull Requests](#pull-requests) 14 | - [Releasing](#releasing) 15 | - [Support](#support) 16 | - [Resources](#resources) 17 | - [Core Contributors](#contributors) 18 | 19 | 20 | ## TLDR; 21 | 22 | - Creating an Issue or Pull Request requires a [GitHub](http://github.com) account. 23 | - Issue reports should be **clear**, **concise** and **reproducible**. Check to see if your issue has already been resolved in the [master]() branch or already reported in Chai's [GitHub Issue Tracker](https://github.com/chaijs/chai/issues). 24 | - Pull Requests must adhere to strict [coding style guidelines](https://github.com/chaijs/chai/wiki/Chai-Coding-Style-Guide). 25 | - In general, avoid submitting PRs for new Assertions without asking core contributors first. More than likely it would be better implemented as a plugin. 26 | - Additional support is available via the [Google Group](http://groups.google.com/group/chaijs) or on irc.freenode.net#chaijs. 27 | - **IMPORTANT**: By submitting a patch, you agree to allow the project owner to license your work under the same license as that used by the project. 28 | 29 | 30 | 31 | 32 | ## Contributing 33 | 34 | The issue tracker is the preferred channel for [bug reports](#bugs), 35 | [feature requests](#features) and [submitting pull 36 | requests](#pull-requests), but please respect the following restrictions: 37 | 38 | * Please **do not** use the issue tracker for personal support requests (use 39 | [Google Group](https://groups.google.com/forum/#!forum/chaijs) or IRC). 40 | * Please **do not** derail or troll issues. Keep the discussion on topic and 41 | respect the opinions of others 42 | 43 | 44 | ### Bug Reports 45 | 46 | A bug is a **demonstrable problem** that is caused by the code in the repository. 47 | 48 | Guidelines for bug reports: 49 | 50 | 1. **Use the GitHub issue search** — check if the issue has already been reported. 51 | 2. **Check if the issue has been fixed** — try to reproduce it using the latest `master` or development branch in the repository. 52 | 3. **Isolate the problem** — create a test case to demonstrate your issue. Provide either a repo, gist, or code sample to demonstrate you problem. 53 | 54 | A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as detailed as possible in your report. What is your environment? What steps will reproduce the issue? What browser(s) and/or Node.js versions experience the problem? What would you expect to be the outcome? All these details will help people to fix any potential bugs. 55 | 56 | Example: 57 | 58 | > Short and descriptive example bug report title 59 | > 60 | > A summary of the issue and the browser/OS environment in which it occurs. If suitable, include the steps required to reproduce the bug. 61 | > 62 | > 1. This is the first step 63 | > 2. This is the second step 64 | > 3. Further steps, etc. 65 | > 66 | > `` - a link to the reduced test case OR 67 | > ```js 68 | > expect(a).to.equal('a'); 69 | > // code sample 70 | > ``` 71 | > 72 | > Any other information you want to share that is relevant to the issue being reported. This might include the lines of code that you have identified as causing the bug, and potential solutions (and your opinions on their merits). 73 | 74 | 75 | ### Feature Requests 76 | 77 | Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to *you* to make a strong case to convince the project's developers of the merits of this feature. Please provide as much detail and context as possible. 78 | 79 | Furthermore, since Chai.js has a [robust plugin API](http://chaijs.com/guide/plugins/), we encourage you to publish **new Assertions** as plugins. If your feature is an enhancement to an **existing Assertion**, please propose your changes as an issue prior to opening a pull request. If the core Chai.js contributors feel your plugin would be better suited as a core assertion, they will invite you to open a PR in [chaijs/chai](https://github.com/chaijs/chai). 80 | 81 | 82 | ### Pull Requests 83 | 84 | - PRs for new core-assertions are advised against. 85 | - PRs for core-assertion bug fixes are always welcome. 86 | - PRs for enhancing the interfaces are always welcome. 87 | - PRs that increase test coverage are always welcome. 88 | - PRs are scrutinized for coding-style. 89 | 90 | Good pull requests - patches, improvements, new features - are a fantastic help. They should remain focused in scope and avoid containing unrelated commits. 91 | 92 | **Please ask first** before embarking on any significant pull request (e.g. implementing features, refactoring code), otherwise you risk spending a lot of time working on something that the project's developers might not want to merge into the project. 93 | 94 | Please adhere to the coding conventions used throughout a project (indentation, accurate comments, etc.) and any other requirements (such as test coverage). Please review the [Chai.js Coding Style Guide](https://github.com/chaijs/chai/wiki/Chai-Coding-Style-Guide). 95 | 96 | Follow this process if you'd like your work considered for inclusion in the project: 97 | 98 | 1. [Fork](http://help.github.com/fork-a-repo/) the project, clone your fork, and configure the remotes: 99 | 100 | ```bash 101 | # Clone your fork of the repo into the current directory 102 | git clone https://github.com// 103 | # Navigate to the newly cloned directory 104 | cd 105 | # Assign the original repo to a remote called "upstream" 106 | git remote add upstream https://github.com// 107 | ``` 108 | 109 | 2. If you cloned a while ago, get the latest changes from upstream: 110 | 111 | ```bash 112 | git checkout 113 | git pull upstream 114 | ``` 115 | 116 | 3. Create a new topic branch (off the main project development branch) to contain your feature, change, or fix: 117 | 118 | ```bash 119 | git checkout -b 120 | ``` 121 | 122 | 4. Commit your changes in logical chunks. Use Git's [interactive rebase](https://help.github.com/articles/interactive-rebase) feature to tidy up your commits before making them public. 123 | 124 | 5. Locally merge (or rebase) the upstream development branch into your topic branch: 125 | 126 | ```bash 127 | git pull [--rebase] upstream 128 | ``` 129 | 130 | 6. Push your topic branch up to your fork: 131 | 132 | ```bash 133 | git push origin 134 | ``` 135 | 136 | 7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title and description. 137 | 138 | **IMPORTANT**: By submitting a patch, you agree to allow the project owner to license your work under the same license as that used by the project. 139 | 140 | 141 | ## Releasing 142 | 143 | Releases can be prepared by any core-contributor or user whom has push access to 144 | the `chaijs/chai` repository. 145 | 146 | This process requires [git-extras](https://github.com/tj/git-extras) for some steps. 147 | 148 | 1. Ensure all tests pass. 149 | 2. Bump the version tag in-code and for all package managers. 150 | - `lib/chai.js` 151 | - `package.json` 152 | - `component.json` 153 | - `bower.json` 154 | 3. Build the browser version with `make`. 155 | 4. Append commit log to `HISTORY.md` using `git changelog` command. 156 | 5. Write human-friendly `ReleaseNotes.md` based on changelog. 157 | - If breaking changes, write migration tutorial(s) and reasoning. 158 | - Callouts for community contributions (PRs) with links to PR and contributing user. 159 | - Callouts for other fixes made by core contributors with links to issue. 160 | 6. Update `README.md` with an updated contributors list using `git summary` command. 161 | 7. Push a tagged release using `git release x.x.x`. 162 | - All tagged releases are published to NPM. 163 | 164 | 165 | ## Support 166 | 167 | 168 | ### Resources 169 | 170 | For most of the documentation you are going to want to visit [ChaiJS.com](http://chaijs.com). 171 | 172 | - [Getting Started Guide](http://chaijs.com/guide/) 173 | - [API Reference](http://chaijs.com/api/) 174 | - [Plugins](http://chaijs.com/plugins/) 175 | 176 | Alternatively, the [wiki](https://github.com/chaijs/chai/wiki) might be what you are looking for. 177 | 178 | - [Chai Coding Style Guide](https://github.com/chaijs/chai/wiki/Chai-Coding-Style-Guide) 179 | - [Third-party Resources](https://github.com/chaijs/chai/wiki/Third-Party-Resources) 180 | 181 | Or finally, you may find a core-contributor or like-minded developer in any of our support channels. 182 | 183 | - IRC: irc.freenode.org #chaijs 184 | - [Mailing List / Google Group](https://groups.google.com/forum/#!forum/chaijs) 185 | 186 | 187 | ### Core Contributors 188 | 189 | Feel free to reach out to any of the core-contributors with you questions or concerns. We will do our best to respond in a timely manner. 190 | 191 | - Jake Luer 192 | - GH: [@logicalparadox](https://github.com/logicalparadox) 193 | - TW: [@jakeluer](http://twitter.com/jakeluer) 194 | - IRC: logicalparadox 195 | - Veselin Todorov 196 | - GH: [@vesln](https://github.com/vesln/) 197 | - TW: [@vesln](http://twitter.com/vesln) 198 | - IRC: vesln 199 | -------------------------------------------------------------------------------- /bower_components/chai/README.md: -------------------------------------------------------------------------------- 1 | [![Chai Documentation](http://chaijs.com/public/img/chai-logo.png)](http://chaijs.com) 2 | 3 | Chai is a BDD / TDD assertion library for [node](http://nodejs.org) and the browser that 4 | can be delightfully paired with any javascript testing framework. 5 | 6 | For more information or to download plugins, view the [documentation](http://chaijs.com). 7 | 8 | [![Build Status](https://travis-ci.org/chaijs/chai.svg?branch=master)](https://travis-ci.org/chaijs/chai) 9 | 10 | [![Selenium Test Status](https://saucelabs.com/browser-matrix/chaijs.svg)](https://saucelabs.com/u/chaijs) 11 | 12 | ### Plugins 13 | 14 | Chai offers a robust Plugin architecture for extending Chai's assertions and interfaces. 15 | 16 | - Need a plugin? View the [official plugin list](http://chaijs.com/plugins). 17 | - Have a plugin and want it listed? Open a Pull Request at [chaijs/chai-docs:plugin.js](https://github.com/chaijs/chai-docs/blob/master/plugins.js#L1-L12). 18 | - Want to build a plugin? Read the [plugin api documentation](http://chaijs.com/guide/plugins/). 19 | 20 | ### Related Projects 21 | 22 | - [chaijs / assertion-error](https://github.com/chaijs/assertion-error): Custom `Error` constructor thrown upon an assertion failing. 23 | - [chaijs / deep-eql](https://github.com/chaijs/deep-eql): Improved deep equality testing for Node.js and the browser. 24 | 25 | ### Contributors 26 | 27 | project : chai 28 | repo age : 3 years, 3 months 29 | active : 224 days 30 | commits : 859 31 | files : 59 32 | authors : 33 | 554 Jake Luer 64.5% 34 | 79 Veselin Todorov 9.2% 35 | 43 Domenic Denicola 5.0% 36 | 29 Keith Cirkel 3.4% 37 | 14 Joshua Perry 1.6% 38 | 8 Chris Polis 0.9% 39 | 6 Ian Zamojc 0.7% 40 | 6 Ruben Verborgh 0.7% 41 | 5 Juliusz Gonera 0.6% 42 | 5 George Kats 0.6% 43 | 5 Jo Liss 0.6% 44 | 5 Scott Nonnenberg 0.6% 45 | 5 leider 0.6% 46 | 4 charlierudolph 0.5% 47 | 4 Chris Jones 0.5% 48 | 4 Max Edmands 0.5% 49 | 4 David da Silva 0.5% 50 | 4 Veselin 0.5% 51 | 4 josher19 0.5% 52 | 4 John Firebaugh 0.5% 53 | 4 Nick Heiner 0.5% 54 | 3 Andrei Neculau 0.3% 55 | 3 Duncan Beevers 0.3% 56 | 3 Ryunosuke SATO 0.3% 57 | 3 Jake Rosoman 0.3% 58 | 3 Jason Karns 0.3% 59 | 3 Jeff Barczewski 0.3% 60 | 2 Jakub Nešetřil 0.2% 61 | 2 Teddy Cross 0.2% 62 | 2 Roman Masek 0.2% 63 | 2 Gregg Lind 0.2% 64 | 2 Edwin Shao 0.2% 65 | 2 Bartvds 0.2% 66 | 1 toastynerd 0.1% 67 | 1 Anand Patil 0.1% 68 | 1 Benjamin Horsleben 0.1% 69 | 1 Brandon Payton 0.1% 70 | 1 Chasen Le Hara 0.1% 71 | 1 Chris Connelly 0.1% 72 | 1 Chris Thompson 0.1% 73 | 1 Christopher Hiller 0.1% 74 | 1 Chun-Yi 0.1% 75 | 1 DD 0.1% 76 | 1 Danilo Vaz 0.1% 77 | 1 Dido Arellano 0.1% 78 | 1 Jeff Welch 0.1% 79 | 1 Jesse McCarthy 0.1% 80 | 1 Julien Wajsberg 0.1% 81 | 1 Kilian Ciuffolo 0.1% 82 | 1 Luís Cardoso 0.1% 83 | 1 Martin Middel 0.1% 84 | 1 Mathias Schreck 0.1% 85 | 1 Michael Lange 0.1% 86 | 1 Niklas Närhinen 0.1% 87 | 1 Paul Miller 0.1% 88 | 1 Refael Ackermann 0.1% 89 | 1 Sasha Koss 0.1% 90 | 1 Victor Costan 0.1% 91 | 1 Vinay Pulim 0.1% 92 | 1 Virginie BARDALES 0.1% 93 | 1 ericdouglas 0.1% 94 | 1 laconbass 0.1% 95 | 1 mohayonao 0.1% 96 | 1 piecioshka 0.1% 97 | 1 shinnn 0.1% 98 | 1 Adam Hull 0.1% 99 | 100 | 101 | ## License 102 | 103 | (The MIT License) 104 | 105 | Copyright (c) 2011-2015 Jake Luer 106 | 107 | Permission is hereby granted, free of charge, to any person obtaining a copy 108 | of this software and associated documentation files (the "Software"), to deal 109 | in the Software without restriction, including without limitation the rights 110 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 111 | copies of the Software, and to permit persons to whom the Software is 112 | furnished to do so, subject to the following conditions: 113 | 114 | The above copyright notice and this permission notice shall be included in 115 | all copies or substantial portions of the Software. 116 | 117 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 118 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 119 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 120 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 121 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 122 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 123 | THE SOFTWARE. 124 | -------------------------------------------------------------------------------- /bower_components/chai/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chai", 3 | "version": "2.1.1", 4 | "description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic.", 5 | "license": "MIT", 6 | "keywords": [ 7 | "test", 8 | "assertion", 9 | "assert", 10 | "testing", 11 | "chai" 12 | ], 13 | "main": "chai.js", 14 | "ignore": [ 15 | "build", 16 | "components", 17 | "lib", 18 | "node_modules", 19 | "support", 20 | "test", 21 | "index.js", 22 | "Makefile", 23 | ".*" 24 | ], 25 | "dependencies": {}, 26 | "devDependencies": {} 27 | } 28 | -------------------------------------------------------------------------------- /bower_components/chai/component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chai" 3 | , "repo": "chaijs/chai" 4 | , "version": "2.1.1" 5 | , "description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic." 6 | , "license": "MIT" 7 | , "keywords": [ 8 | "test" 9 | , "assertion" 10 | , "assert" 11 | , "testing" 12 | , "chai" 13 | ] 14 | , "main": "index.js" 15 | , "scripts": [ 16 | "index.js" 17 | , "lib/chai.js" 18 | , "lib/chai/assertion.js" 19 | , "lib/chai/config.js" 20 | , "lib/chai/core/assertions.js" 21 | , "lib/chai/interface/assert.js" 22 | , "lib/chai/interface/expect.js" 23 | , "lib/chai/interface/should.js" 24 | , "lib/chai/utils/addChainableMethod.js" 25 | , "lib/chai/utils/addMethod.js" 26 | , "lib/chai/utils/addProperty.js" 27 | , "lib/chai/utils/flag.js" 28 | , "lib/chai/utils/getActual.js" 29 | , "lib/chai/utils/getEnumerableProperties.js" 30 | , "lib/chai/utils/getMessage.js" 31 | , "lib/chai/utils/getName.js" 32 | , "lib/chai/utils/getPathValue.js" 33 | , "lib/chai/utils/getPathInfo.js" 34 | , "lib/chai/utils/hasProperty.js" 35 | , "lib/chai/utils/getProperties.js" 36 | , "lib/chai/utils/index.js" 37 | , "lib/chai/utils/inspect.js" 38 | , "lib/chai/utils/objDisplay.js" 39 | , "lib/chai/utils/overwriteMethod.js" 40 | , "lib/chai/utils/overwriteProperty.js" 41 | , "lib/chai/utils/overwriteChainableMethod.js" 42 | , "lib/chai/utils/test.js" 43 | , "lib/chai/utils/transferFlags.js" 44 | , "lib/chai/utils/type.js" 45 | ] 46 | , "dependencies": { 47 | "chaijs/assertion-error": "1.0.0" 48 | , "chaijs/deep-eql": "0.1.3" 49 | } 50 | , "development": {} 51 | } 52 | -------------------------------------------------------------------------------- /bower_components/chai/karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function(config) { 2 | config.set({ 3 | frameworks: [ 'mocha' ] 4 | , files: [ 5 | 'build/build.js' 6 | , 'test/bootstrap/karma.js' 7 | , 'test/*.js' 8 | ] 9 | , reporters: [ 'progress' ] 10 | , colors: true 11 | , logLevel: config.LOG_INFO 12 | , autoWatch: false 13 | , browsers: [ 'PhantomJS' ] 14 | , browserDisconnectTimeout: 10000 15 | , browserDisconnectTolerance: 2 16 | , browserNoActivityTimeout: 20000 17 | , singleRun: true 18 | }); 19 | 20 | switch (process.env.CHAI_TEST_ENV) { 21 | case 'sauce': 22 | require('./karma.sauce')(config); 23 | break; 24 | default: 25 | // ... 26 | break; 27 | }; 28 | }; 29 | -------------------------------------------------------------------------------- /bower_components/chai/karma.sauce.js: -------------------------------------------------------------------------------- 1 | var version = require('./package.json').version; 2 | var ts = new Date().getTime(); 3 | 4 | module.exports = function(config) { 5 | var auth; 6 | 7 | try { 8 | auth = require('./test/auth/index'); 9 | } catch(ex) { 10 | auth = {}; 11 | auth.SAUCE_USERNAME = process.env.SAUCE_USERNAME || null; 12 | auth.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY || null; 13 | } 14 | 15 | if (!auth.SAUCE_USERNAME || !auth.SAUCE_ACCESS_KEY) return; 16 | if (process.env.SKIP_SAUCE) return; 17 | 18 | var branch = process.env.TRAVIS_BRANCH || 'local' 19 | var browserConfig = require('./sauce.browsers'); 20 | var browsers = Object.keys(browserConfig); 21 | var tags = [ 'chaijs_' + version, auth.SAUCE_USERNAME + '@' + branch ]; 22 | var tunnel = process.env.TRAVIS_JOB_NUMBER || ts; 23 | 24 | if (process.env.TRAVIS_JOB_NUMBER) { 25 | tags.push('travis@' + process.env.TRAVIS_JOB_NUMBER); 26 | } 27 | 28 | config.browsers = config.browsers.concat(browsers); 29 | config.customLaunchers = browserConfig; 30 | config.reporters.push('saucelabs'); 31 | config.transports = [ 'xhr-polling' ]; 32 | 33 | config.sauceLabs = { 34 | username: auth.SAUCE_USERNAME 35 | , accessKey: auth.SAUCE_ACCESS_KEY 36 | , startConnect: true 37 | , tags: tags 38 | , testName: 'ChaiJS' 39 | , tunnelIdentifier: tunnel 40 | }; 41 | }; 42 | -------------------------------------------------------------------------------- /bower_components/chai/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Jake Luer ", 3 | "name": "chai", 4 | "description": "BDD/TDD assertion library for node.js and the browser. Test framework agnostic.", 5 | "keywords": [ 6 | "test", 7 | "assertion", 8 | "assert", 9 | "testing", 10 | "chai" 11 | ], 12 | "homepage": "http://chaijs.com", 13 | "license": "MIT", 14 | "contributors": [ 15 | "Jake Luer ", 16 | "Domenic Denicola (http://domenicdenicola.com)", 17 | "Veselin Todorov ", 18 | "John Firebaugh " 19 | ], 20 | "version": "2.1.1", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/chaijs/chai" 24 | }, 25 | "bugs": { 26 | "url": "https://github.com/chaijs/chai/issues" 27 | }, 28 | "main": "./index", 29 | "scripts": { 30 | "test": "make test" 31 | }, 32 | "engines": { 33 | "node": ">= 0.4.0" 34 | }, 35 | "dependencies": { 36 | "assertion-error": "1.0.0", 37 | "deep-eql": "0.1.3" 38 | }, 39 | "devDependencies": { 40 | "component": "*", 41 | "karma": "0.12.x", 42 | "karma-mocha": "*", 43 | "karma-sauce-launcher": "0.2.x", 44 | "karma-phantomjs-launcher": "0.1.1", 45 | "mocha": "1.21.x", 46 | "istanbul": "0.2.x" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /bower_components/chai/sauce.browsers.js: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * Chrome 4 | */ 5 | 6 | exports['SL_Chrome'] = { 7 | base: 'SauceLabs' 8 | , browserName: 'chrome' 9 | }; 10 | 11 | /*! 12 | * Firefox 13 | */ 14 | 15 | /*! 16 | * TODO: Karma doesn't seem to like this, though sauce boots its up 17 | * 18 | 19 | exports['SL_Firefox_23'] = { 20 | base: 'SauceLabs' 21 | , browserName: 'firefox' 22 | , platform: 'Windows XP' 23 | , version: '23' 24 | }; 25 | 26 | */ 27 | 28 | exports['SL_Firefox_22'] = { 29 | base: 'SauceLabs' 30 | , browserName: 'firefox' 31 | , platform: 'Windows 7' 32 | , version: '22' 33 | }; 34 | 35 | /*! 36 | * Opera 37 | */ 38 | 39 | exports['SL_Opera_12'] = { 40 | base: 'SauceLabs' 41 | , browserName: 'opera' 42 | , platform: 'Windows 7' 43 | , version: '12' 44 | }; 45 | 46 | exports['SL_Opera_11'] = { 47 | base: 'SauceLabs' 48 | , browserName: 'opera' 49 | , platform: 'Windows 7' 50 | , version: '11' 51 | }; 52 | 53 | /*! 54 | * Internet Explorer 55 | */ 56 | 57 | exports['SL_IE_10'] = { 58 | base: 'SauceLabs' 59 | , browserName: 'internet explorer' 60 | , platform: 'Windows 2012' 61 | , version: '10' 62 | }; 63 | 64 | /*! 65 | * Safari 66 | */ 67 | 68 | exports['SL_Safari_6'] = { 69 | base: 'SauceLabs' 70 | , browserName: 'safari' 71 | , platform: 'Mac 10.8' 72 | , version: '6' 73 | }; 74 | 75 | exports['SL_Safari_5'] = { 76 | base: 'SauceLabs' 77 | , browserName: 'safari' 78 | , platform: 'Mac 10.6' 79 | , version: '5' 80 | }; 81 | 82 | /*! 83 | * iPhone 84 | */ 85 | 86 | /*! 87 | * TODO: These take forever to boot or shut down. Causes timeout. 88 | * 89 | 90 | exports['SL_iPhone_6'] = { 91 | base: 'SauceLabs' 92 | , browserName: 'iphone' 93 | , platform: 'Mac 10.8' 94 | , version: '6' 95 | }; 96 | 97 | exports['SL_iPhone_5-1'] = { 98 | base: 'SauceLabs' 99 | , browserName: 'iphone' 100 | , platform: 'Mac 10.8' 101 | , version: '5.1' 102 | }; 103 | 104 | exports['SL_iPhone_5'] = { 105 | base: 'SauceLabs' 106 | , browserName: 'iphone' 107 | , platform: 'Mac 10.6' 108 | , version: '5' 109 | }; 110 | 111 | */ 112 | 113 | /*! 114 | * Android 115 | */ 116 | 117 | /*! 118 | * TODO: fails because of error serialization 119 | * 120 | 121 | exports['SL_Android_4'] = { 122 | base: 'SauceLabs' 123 | , browserName: 'android' 124 | , platform: 'Linux' 125 | , version: '4' 126 | }; 127 | 128 | */ 129 | -------------------------------------------------------------------------------- /bower_components/mocha/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mocha", 3 | "version": "2.2.1", 4 | "homepage": "http://mocha.github.io/mocha", 5 | "description": "simple, flexible, fun test framework", 6 | "authors": [ 7 | "TJ Holowaychuk ", 8 | "Joshua Appelman ", 9 | "Oleg Gaidarenko ", 10 | "Christoffer Hallas ", 11 | "Christopher Hiller ", 12 | "Travis Jeffery ", 13 | "Johnathan Ong ", 14 | "Guillermo Rauch " 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git://github.com/mochajs/mocha.git" 19 | }, 20 | "main": [ 21 | "mocha.js", 22 | "mocha.css" 23 | ], 24 | "ignore": [ 25 | "bin", 26 | "editors", 27 | "images", 28 | "lib", 29 | "support", 30 | "test", 31 | ".gitignore", 32 | ".npmignore", 33 | ".travis.yml", 34 | "component.json", 35 | "index.js", 36 | "Makefile", 37 | "package.json" 38 | ], 39 | "keywords": [ 40 | "mocha", 41 | "test", 42 | "bdd", 43 | "tdd", 44 | "tap" 45 | ], 46 | "license": "MIT", 47 | "_release": "2.2.1", 48 | "_resolution": { 49 | "type": "version", 50 | "tag": "2.2.1", 51 | "commit": "3102c9bc395c3a542b492fb56011a3eba15f3b76" 52 | }, 53 | "_source": "git://github.com/mochajs/mocha.git", 54 | "_target": "~2.2.1", 55 | "_originalSource": "mocha", 56 | "_direct": true 57 | } -------------------------------------------------------------------------------- /bower_components/mocha/.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | # editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | charset = utf-8 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [Makefile] 15 | indent_style = tab 16 | 17 | [*.md] 18 | trim_trailing_whitespace = false 19 | -------------------------------------------------------------------------------- /bower_components/mocha/.mailmap: -------------------------------------------------------------------------------- 1 | TJ Holowaychuk -------------------------------------------------------------------------------- /bower_components/mocha/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Mocha 2 | 3 | Hi! We could use your help. Let us help you help us. Or something. 4 | 5 | ## General 6 | 7 | 1. If you are looking for a place to begin, **please send PRs for bugfixes instead of new features**, and/or **look for issues labeled `PR PLEASE`.** 8 | 9 | 2. **Help with documentation and the wiki is always appreciated**. 10 | 11 | 3. Please **be courteous and constructive** when commenting on issues, commits, and pull requests. 12 | 13 | ## Bug Reports & Issues 14 | 15 | 1. When reporting a bug, please **provide steps to reproduce**. If possible, show code. 16 | 17 | 2. Please **show all code in JavaScript**. We don't all read ``. If you do not, you will be asked to. 18 | 19 | 3. Because Mocha works with many third-party libraries and tools, **ensure the bug you are reporting is actually within Mocha**. 20 | 21 | 4. If you report a bug, and it is inactive for a significant amount of time, it may be closed. **Please respond promptly to requests for more information**. 22 | 23 | ## Pull Requests 24 | 25 | 1. Before sending a large PR, it's recommended to **create an issue to propose the change**. Nobody wants to write a book of code and throw it away. 26 | 27 | 2. Because Mocha should be kept as maintainable as possible, its codebase must be kept slim. Historically, *most PRs for new features are not merged*. New features inevitably increase the size of the codebase, and thus reduce maintainability. Only features *deemed essential* are likely to be merged--this is at the discretion of the maintainer(s). If your PR for a feature is not merged, this doesn't necessarily mean your PR was a bad idea, wouldn't be used, or otherwise sucks. It just means **only essential PRs for new features are likely to be merged**. 28 | 29 | 3. Due to the above, before creating a PR for a new feature, **create an issue to propose the feature.** 30 | 31 | 4. Please **respect existing coding conventions**, whatever those may be. 32 | 33 | 5. If your PR has been waiting in limbo for some time, it's very helpful to **rebase against master**, which will make it easier to merge. 34 | 35 | 6. Please **add tests for new code**. 36 | 37 | 7. **Always run `npm test` before sending a PR.** If you break the tests, your PR will not be accepted until they are fixed. 38 | 39 | ## Source Control 40 | 41 | 1. Please **squash your commits** when sending a pull request. If you are unfamiliar with this process, see [this guide](https://help.github.com/articles/about-git-rebase/). If you have already pushed your changesets and are squashing thereafter, this may necessitate the use of a "force push". Please [read the docs](http://git-scm.com/docs/git-push) before you attempt this. 42 | 43 | 2. Please **follow the commit message conventions [outlined here](https://medium.com/code-adventures/git-conventions-a940ee20862d).** 44 | 45 | ## TL;DR 46 | 47 | **Be kind, be diligent, look before you leap into a PR, and follow common community conventions**. 48 | 49 | *- The Mocha Team* 50 | -------------------------------------------------------------------------------- /bower_components/mocha/LICENSE: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2011-2015 TJ Holowaychuk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /bower_components/mocha/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://api.travis-ci.org/mochajs/mocha.svg?branch=master)](http://travis-ci.org/mochajs/mocha) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mochajs/mocha?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 2 | 3 | [![Mocha test framework](http://f.cl.ly/items/3l1k0n2A1U3M1I1L210p/Screen%20Shot%202012-02-24%20at%202.21.43%20PM.png)](http://mochajs.org) 4 | 5 | Mocha is a simple, flexible, fun JavaScript test framework for node.js and the browser. For more information view the [documentation](http://mochajs.org). 6 | 7 | ## Contributors 8 | 9 | ``` 10 | project : mocha 11 | repo age : 3 years, 4 months 12 | active : 509 days 13 | commits : 1575 14 | files : 153 15 | authors : 16 | 977 TJ Holowaychuk 62.0% 17 | 132 Travis Jeffery 8.4% 18 | 63 Christopher Hiller 4.0% 19 | 31 Guillermo Rauch 2.0% 20 | 27 Joshua Appelman 1.7% 21 | 13 Attila Domokos 0.8% 22 | 10 John Firebaugh 0.6% 23 | 8 Nathan Rajlich 0.5% 24 | 8 Jo Liss 0.5% 25 | 6 Mike Pennisi 0.4% 26 | 6 Brendan Nee 0.4% 27 | 6 James Carr 0.4% 28 | 5 Aaron Heckmann 0.3% 29 | 5 Raynos 0.3% 30 | 5 Ryunosuke SATO 0.3% 31 | 4 hokaccha 0.3% 32 | 4 Jonathan Ong 0.3% 33 | 4 Joshua Krall 0.3% 34 | 4 Domenic Denicola 0.3% 35 | 4 Forbes Lindesay 0.3% 36 | 4 Xavier Antoviaque 0.3% 37 | 4 David da Silva 0.3% 38 | 3 Ariel Mashraki 0.2% 39 | 3 Ben Bradley 0.2% 40 | 3 Merrick Christensen 0.2% 41 | 3 Andreas Lind Petersen 0.2% 42 | 3 Nathan Bowser 0.2% 43 | 3 Cory Thomas 0.2% 44 | 3 Benjie Gillam 0.2% 45 | 3 Wil Moore III 0.2% 46 | 3 Ben Lindsey 0.2% 47 | 3 Tyson Tate 0.2% 48 | 3 Paul Miller 0.2% 49 | 3 eiji.ienaga 0.2% 50 | 3 Mathieu Desvé 0.2% 51 | 3 Jesse Dailey 0.2% 52 | 3 fool2fish 0.2% 53 | 3 Fredrik Enestad 0.2% 54 | 3 Sindre Sorhus 0.2% 55 | 3 Valentin Agachi 0.2% 56 | 2 jsdevel 0.1% 57 | 2 Arian Stolwijk 0.1% 58 | 2 Juzer Ali 0.1% 59 | 2 David Henderson 0.1% 60 | 2 Justin DuJardin 0.1% 61 | 2 Paul Armstrong 0.1% 62 | 2 Pete Hawkins 0.1% 63 | 2 Jonas Westerlund 0.1% 64 | 2 Quang Van 0.1% 65 | 2 Simon Gaeremynck 0.1% 66 | 2 travis jeffery 0.1% 67 | 2 Dominique Quatravaux 0.1% 68 | 2 Jacob Wejendorp 0.1% 69 | 2 Shawn Krisman 0.1% 70 | 2 FARKAS Máté 0.1% 71 | 2 Konstantin Käfer 0.1% 72 | 2 Timo Tijhof 0.1% 73 | 2 Sean Lang 0.1% 74 | 2 Quanlong He 0.1% 75 | 2 Glen Mailer 0.1% 76 | 2 Alexander Early 0.1% 77 | 2 Ian Storm Taylor 0.1% 78 | 2 Brian Beck 0.1% 79 | 2 Michael Riley 0.1% 80 | 2 Michael Schoonmaker 0.1% 81 | 2 domenic 0.1% 82 | 2 fcrisci 0.1% 83 | 2 Buck Doyle 0.1% 84 | 2 Nathan Alderson 0.1% 85 | 1 Mal Graty 0.1% 86 | 1 Marc Kuo 0.1% 87 | 1 Matija Marohnić 0.1% 88 | 1 Matt Robenolt 0.1% 89 | 1 Matt Smith 0.1% 90 | 1 Matthew Shanley 0.1% 91 | 1 Mattias Tidlund 0.1% 92 | 1 Michael Jackson 0.1% 93 | 1 Michael Olson 0.1% 94 | 1 Michal Charemza 0.1% 95 | 1 Nathan Black 0.1% 96 | 1 Nick Fitzgerald 0.1% 97 | 1 Noshir Patel 0.1% 98 | 1 Panu Horsmalahti 0.1% 99 | 1 Phil Sung 0.1% 100 | 1 R56 0.1% 101 | 1 Refael Ackermann 0.1% 102 | 1 Richard Dingwall 0.1% 103 | 1 Richard Knop 0.1% 104 | 1 Rob Wu 0.1% 105 | 1 Romain Prieto 0.1% 106 | 1 Roman Neuhauser 0.1% 107 | 1 Roman Shtylman 0.1% 108 | 1 Russ Bradberry 0.1% 109 | 1 Russell Munson 0.1% 110 | 1 Rustem Mustafin 0.1% 111 | 1 Salehen Shovon Rahman 0.1% 112 | 1 Sasha Koss 0.1% 113 | 1 Seiya Konno 0.1% 114 | 1 Shaine Hatch 0.1% 115 | 1 Simon Goumaz 0.1% 116 | 1 Standa Opichal 0.1% 117 | 1 Stephen Mathieson 0.1% 118 | 1 Steve Mason 0.1% 119 | 1 Tapiwa Kelvin 0.1% 120 | 1 Teddy Zeenny 0.1% 121 | 1 Tim Ehat 0.1% 122 | 1 Vadim Nikitin 0.1% 123 | 1 Victor Costan 0.1% 124 | 1 Will Langstroth 0.1% 125 | 1 Yanis Wang 0.1% 126 | 1 Yuest Wang 0.1% 127 | 1 Zsolt Takács 0.1% 128 | 1 abrkn 0.1% 129 | 1 airportyh 0.1% 130 | 1 badunk 0.1% 131 | 1 claudyus 0.1% 132 | 1 dasilvacontin 0.1% 133 | 1 fengmk2 0.1% 134 | 1 gaye 0.1% 135 | 1 grasGendarme 0.1% 136 | 1 lakmeer 0.1% 137 | 1 lodr 0.1% 138 | 1 mrShturman 0.1% 139 | 1 nishigori 0.1% 140 | 1 omardelarosa 0.1% 141 | 1 qiuzuhui 0.1% 142 | 1 samuel goldszmidt 0.1% 143 | 1 sebv 0.1% 144 | 1 startswithaj 0.1% 145 | 1 tgautier@yahoo.com 0.1% 146 | 1 traleig1 0.1% 147 | 1 vlad 0.1% 148 | 1 yuitest 0.1% 149 | 1 zhiyelee 0.1% 150 | 1 Adam Crabtree 0.1% 151 | 1 Andreas Brekken 0.1% 152 | 1 Andrew Nesbitt 0.1% 153 | 1 Andrey Popp 0.1% 154 | 1 Arnaud Brousseau 0.1% 155 | 1 Atsuya Takagi 0.1% 156 | 1 Austin Birch 0.1% 157 | 1 Ben Noordhuis 0.1% 158 | 1 Bjørge Næss 0.1% 159 | 1 Brian Lalor 0.1% 160 | 1 Brian M. Carlson 0.1% 161 | 1 Brian Moore 0.1% 162 | 1 Bryan Donovan 0.1% 163 | 1 C. Scott Ananian 0.1% 164 | 1 Casey Foster 0.1% 165 | 1 ChrisWren 0.1% 166 | 1 Connor Dunn 0.1% 167 | 1 Corey Butler 0.1% 168 | 1 Daniel Stockman 0.1% 169 | 1 Dave McKenna 0.1% 170 | 1 Denis Bardadym 0.1% 171 | 1 Devin Weaver 0.1% 172 | 1 Di Wu 0.1% 173 | 1 Diogo Monteiro 0.1% 174 | 1 Dmitry Shirokov 0.1% 175 | 1 Dr. Travis Jeffery 0.1% 176 | 1 Fedor Indutny 0.1% 177 | 1 Florian Margaine 0.1% 178 | 1 Frederico Silva 0.1% 179 | 1 Fredrik Lindin 0.1% 180 | 1 Gareth Aye 0.1% 181 | 1 Gareth Murphy 0.1% 182 | 1 Gavin Mogan 0.1% 183 | 1 Giovanni Bassi 0.1% 184 | 1 Glen Huang 0.1% 185 | 1 Greg Perkins 0.1% 186 | 1 Harish 0.1% 187 | 1 Harry Brundage 0.1% 188 | 1 Herman Junge 0.1% 189 | 1 Ian Young 0.1% 190 | 1 Ivan 0.1% 191 | 1 JP Bochi 0.1% 192 | 1 Jaakko Salonen 0.1% 193 | 1 Jakub Nešetřil 0.1% 194 | 1 James Bowes 0.1% 195 | 1 James Lal 0.1% 196 | 1 Jan Kopriva 0.1% 197 | 1 Jason Barry 0.1% 198 | 1 Javier Aranda 0.1% 199 | 1 Jean Ponchon 0.1% 200 | 1 Jeff Kunkle 0.1% 201 | 1 Jeremy Martin 0.1% 202 | 1 Jimmy Cuadra 0.1% 203 | 1 John Doty 0.1% 204 | 1 Jonathan Creamer 0.1% 205 | 1 Jonathan Park 0.1% 206 | 1 Jussi Virtanen 0.1% 207 | 1 Katie Gengler 0.1% 208 | 1 Kazuhito Hokamura 0.1% 209 | 1 Kent C. Dodds 0.1% 210 | 1 Kevin Conway 0.1% 211 | 1 Kirill Korolyov 0.1% 212 | 1 Koen Punt 0.1% 213 | 1 Laszlo Bacsi 0.1% 214 | 1 Liam Newman 0.1% 215 | 1 Linus Unnebäck 0.1% 216 | 1 László Bácsi 0.1% 217 | 1 Maciej Małecki 0.1% 218 | ``` 219 | 220 | ## Links 221 | 222 | - [Google Group](http://groups.google.com/group/mochajs) 223 | - [Wiki](https://github.com/mochajs/mocha/wiki) 224 | - Mocha [Extensions and reporters](https://github.com/mochajs/mocha/wiki) 225 | -------------------------------------------------------------------------------- /bower_components/mocha/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mocha", 3 | "version": "2.2.1", 4 | "homepage": "http://mocha.github.io/mocha", 5 | "description": "simple, flexible, fun test framework", 6 | "authors": [ 7 | "TJ Holowaychuk ", 8 | "Joshua Appelman ", 9 | "Oleg Gaidarenko ", 10 | "Christoffer Hallas ", 11 | "Christopher Hiller ", 12 | "Travis Jeffery ", 13 | "Johnathan Ong ", 14 | "Guillermo Rauch " 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git://github.com/mochajs/mocha.git" 19 | }, 20 | "main": [ 21 | "mocha.js", 22 | "mocha.css" 23 | ], 24 | "ignore": [ 25 | "bin", 26 | "editors", 27 | "images", 28 | "lib", 29 | "support", 30 | "test", 31 | ".gitignore", 32 | ".npmignore", 33 | ".travis.yml", 34 | "component.json", 35 | "index.js", 36 | "Makefile", 37 | "package.json" 38 | ], 39 | "keywords": [ 40 | "mocha", 41 | "test", 42 | "bdd", 43 | "tdd", 44 | "tap" 45 | ], 46 | "license": "MIT" 47 | } -------------------------------------------------------------------------------- /bower_components/mocha/media/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | mocha 7 | 8 | -------------------------------------------------------------------------------- /bower_components/mocha/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | body { 4 | margin:0; 5 | } 6 | 7 | #mocha { 8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | margin: 60px 50px; 10 | } 11 | 12 | #mocha ul, 13 | #mocha li { 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | #mocha ul { 19 | list-style: none; 20 | } 21 | 22 | #mocha h1, 23 | #mocha h2 { 24 | margin: 0; 25 | } 26 | 27 | #mocha h1 { 28 | margin-top: 15px; 29 | font-size: 1em; 30 | font-weight: 200; 31 | } 32 | 33 | #mocha h1 a { 34 | text-decoration: none; 35 | color: inherit; 36 | } 37 | 38 | #mocha h1 a:hover { 39 | text-decoration: underline; 40 | } 41 | 42 | #mocha .suite .suite h1 { 43 | margin-top: 0; 44 | font-size: .8em; 45 | } 46 | 47 | #mocha .hidden { 48 | display: none; 49 | } 50 | 51 | #mocha h2 { 52 | font-size: 12px; 53 | font-weight: normal; 54 | cursor: pointer; 55 | } 56 | 57 | #mocha .suite { 58 | margin-left: 15px; 59 | } 60 | 61 | #mocha .test { 62 | margin-left: 15px; 63 | overflow: hidden; 64 | } 65 | 66 | #mocha .test.pending:hover h2::after { 67 | content: '(pending)'; 68 | font-family: arial, sans-serif; 69 | } 70 | 71 | #mocha .test.pass.medium .duration { 72 | background: #c09853; 73 | } 74 | 75 | #mocha .test.pass.slow .duration { 76 | background: #b94a48; 77 | } 78 | 79 | #mocha .test.pass::before { 80 | content: '✓'; 81 | font-size: 12px; 82 | display: block; 83 | float: left; 84 | margin-right: 5px; 85 | color: #00d6b2; 86 | } 87 | 88 | #mocha .test.pass .duration { 89 | font-size: 9px; 90 | margin-left: 5px; 91 | padding: 2px 5px; 92 | color: #fff; 93 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 94 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 95 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 96 | -webkit-border-radius: 5px; 97 | -moz-border-radius: 5px; 98 | -ms-border-radius: 5px; 99 | -o-border-radius: 5px; 100 | border-radius: 5px; 101 | } 102 | 103 | #mocha .test.pass.fast .duration { 104 | display: none; 105 | } 106 | 107 | #mocha .test.pending { 108 | color: #0b97c4; 109 | } 110 | 111 | #mocha .test.pending::before { 112 | content: '◦'; 113 | color: #0b97c4; 114 | } 115 | 116 | #mocha .test.fail { 117 | color: #c00; 118 | } 119 | 120 | #mocha .test.fail pre { 121 | color: black; 122 | } 123 | 124 | #mocha .test.fail::before { 125 | content: '✖'; 126 | font-size: 12px; 127 | display: block; 128 | float: left; 129 | margin-right: 5px; 130 | color: #c00; 131 | } 132 | 133 | #mocha .test pre.error { 134 | color: #c00; 135 | max-height: 300px; 136 | overflow: auto; 137 | } 138 | 139 | /** 140 | * (1): approximate for browsers not supporting calc 141 | * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) 142 | * ^^ seriously 143 | */ 144 | #mocha .test pre { 145 | display: block; 146 | float: left; 147 | clear: left; 148 | font: 12px/1.5 monaco, monospace; 149 | margin: 5px; 150 | padding: 15px; 151 | border: 1px solid #eee; 152 | max-width: 85%; /*(1)*/ 153 | max-width: calc(100% - 42px); /*(2)*/ 154 | word-wrap: break-word; 155 | border-bottom-color: #ddd; 156 | -webkit-border-radius: 3px; 157 | -webkit-box-shadow: 0 1px 3px #eee; 158 | -moz-border-radius: 3px; 159 | -moz-box-shadow: 0 1px 3px #eee; 160 | border-radius: 3px; 161 | } 162 | 163 | #mocha .test h2 { 164 | position: relative; 165 | } 166 | 167 | #mocha .test a.replay { 168 | position: absolute; 169 | top: 3px; 170 | right: 0; 171 | text-decoration: none; 172 | vertical-align: middle; 173 | display: block; 174 | width: 15px; 175 | height: 15px; 176 | line-height: 15px; 177 | text-align: center; 178 | background: #eee; 179 | font-size: 15px; 180 | -moz-border-radius: 15px; 181 | border-radius: 15px; 182 | -webkit-transition: opacity 200ms; 183 | -moz-transition: opacity 200ms; 184 | transition: opacity 200ms; 185 | opacity: 0.3; 186 | color: #888; 187 | } 188 | 189 | #mocha .test:hover a.replay { 190 | opacity: 1; 191 | } 192 | 193 | #mocha-report.pass .test.fail { 194 | display: none; 195 | } 196 | 197 | #mocha-report.fail .test.pass { 198 | display: none; 199 | } 200 | 201 | #mocha-report.pending .test.pass, 202 | #mocha-report.pending .test.fail { 203 | display: none; 204 | } 205 | #mocha-report.pending .test.pass.pending { 206 | display: block; 207 | } 208 | 209 | #mocha-error { 210 | color: #c00; 211 | font-size: 1.5em; 212 | font-weight: 100; 213 | letter-spacing: 1px; 214 | } 215 | 216 | #mocha-stats { 217 | position: fixed; 218 | top: 15px; 219 | right: 10px; 220 | font-size: 12px; 221 | margin: 0; 222 | color: #888; 223 | z-index: 1; 224 | } 225 | 226 | #mocha-stats .progress { 227 | float: right; 228 | padding-top: 0; 229 | } 230 | 231 | #mocha-stats em { 232 | color: black; 233 | } 234 | 235 | #mocha-stats a { 236 | text-decoration: none; 237 | color: inherit; 238 | } 239 | 240 | #mocha-stats a:hover { 241 | border-bottom: 1px solid #eee; 242 | } 243 | 244 | #mocha-stats li { 245 | display: inline-block; 246 | margin: 0 5px; 247 | list-style: none; 248 | padding-top: 11px; 249 | } 250 | 251 | #mocha-stats canvas { 252 | width: 40px; 253 | height: 40px; 254 | } 255 | 256 | #mocha code .comment { color: #ddd; } 257 | #mocha code .init { color: #2f6fad; } 258 | #mocha code .string { color: #5890ad; } 259 | #mocha code .keyword { color: #8a6343; } 260 | #mocha code .number { color: #2f6fad; } 261 | 262 | @media screen and (max-device-width: 480px) { 263 | #mocha { 264 | margin: 60px 0px; 265 | } 266 | 267 | #mocha #stats { 268 | position: absolute; 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /demo/app.css: -------------------------------------------------------------------------------- 1 | input { 2 | width: auto; } 3 | 4 | input.command-search { 5 | width: 100px; } 6 | 7 | *[disabled] 8 | .disable, span.disable { 9 | color: gray; 10 | font-style: italic; } 11 | 12 | .invalid, input.invalid { 13 | border: 1px solid red; } 14 | 15 | .inline-block { 16 | display: inline-block; } 17 | 18 | img { 19 | display: inline-block; } 20 | 21 | div { 22 | font-size: 20px; 23 | margin: 0 0 0 0; 24 | padding: 0 0 0 0; 25 | border: 0; } 26 | 27 | body { 28 | overflow: hidden; } 29 | 30 | body { 31 | position: absolute; 32 | top: 0px; 33 | left: 0px; 34 | bottom: 0px; 35 | right: 0px; } 36 | 37 | @-webkit-keyframes dcdialog-fadeout { 38 | 0% { 39 | opacity: 1; } 40 | 100% { 41 | opacity: 0; } } 42 | 43 | @keyframes dcdialog-fadeout { 44 | 0% { 45 | opacity: 1; } 46 | 100% { 47 | opacity: 0; } } 48 | 49 | @-webkit-keyframes dcdialog-fadein { 50 | 0% { 51 | opacity: 0; } 52 | 100% { 53 | opacity: 1; } } 54 | 55 | @keyframes dcdialog-fadein { 56 | 0% { 57 | opacity: 0; } 58 | 100% { 59 | opacity: 1; } } 60 | 61 | .dcdialog, .dcdialog *, .dcdialog :after, .dcdialog :before { 62 | -webkit-box-sizing: border-box; 63 | -moz-box-sizing: border-box; 64 | box-sizing: border-box; } 65 | 66 | .dcdialog { 67 | position: fixed; 68 | overflow: auto; 69 | -webkit-overflow-scrolling: touch; 70 | z-index: 10000; 71 | top: 0; 72 | right: 0; 73 | bottom: 0; 74 | left: 0; } 75 | 76 | .dcdialog-overlay { 77 | position: fixed; 78 | background: rgba(0, 0, 0, 0.4); 79 | top: 0; 80 | right: 0; 81 | bottom: 0; 82 | left: 0; 83 | -webkit-backface-visibility: hidden; 84 | -webkit-animation: dcdialog-fadein 0.5s; 85 | animation: dcdialog-fadein 0.5s; } 86 | 87 | .dcdialog.dcdialog-closing .dcdialog-overlay { 88 | -webkit-backface-visibility: hidden; 89 | -webkit-animation: dcdialog-fadeout 0.5s; 90 | animation: dcdialog-fadeout 0.5s; } 91 | 92 | .dcdialog-content { 93 | background: #fff; 94 | -webkit-backface-visibility: hidden; 95 | -webkit-animation: dcdialog-fadein 0.5s; 96 | animation: dcdialog-fadein 0.5s; } 97 | 98 | .dcdialog.dcdialog-closing .dcdialog-content { 99 | -webkit-backface-visibility: hidden; 100 | -webkit-animation: dcdialog-fadeout 0.5s; 101 | animation: dcdialog-fadeout 0.5s; } 102 | 103 | .dcdialog-close:before { 104 | font-family: Helvetica, Arial, sans-serif; 105 | content: '\00D7'; 106 | cursor: pointer; } 107 | 108 | body.dcdialog-open { 109 | overflow: hidden; } 110 | 111 | @-webkit-keyframes dcdialog-flyin { 112 | 0% { 113 | opacity: 0; 114 | -webkit-transform: translateY(-40px); 115 | transform: translateY(-40px); } 116 | 100% { 117 | opacity: 1; 118 | -webkit-transform: translateY(0); 119 | transform: translateY(0); } } 120 | 121 | @keyframes dcdialog-flyin { 122 | 0% { 123 | opacity: 0; 124 | -webkit-transform: translateY(-40px); 125 | -ms-transform: translateY(-40px); 126 | transform: translateY(-40px); } 127 | 100% { 128 | opacity: 1; 129 | -webkit-transform: translateY(0); 130 | -ms-transform: translateY(0); 131 | transform: translateY(0); } } 132 | 133 | @-webkit-keyframes dcdialog-flyout { 134 | 0% { 135 | opacity: 1; 136 | -webkit-transform: translateY(0); 137 | transform: translateY(0); } 138 | 100% { 139 | opacity: 0; 140 | -webkit-transform: translateY(-40px); 141 | transform: translateY(-40px); } } 142 | 143 | @keyframes dcdialog-flyout { 144 | 0% { 145 | opacity: 1; 146 | -webkit-transform: translateY(0); 147 | -ms-transform: translateY(0); 148 | transform: translateY(0); } 149 | 100% { 150 | opacity: 0; 151 | -webkit-transform: translateY(-40px); 152 | -ms-transform: translateY(-40px); 153 | transform: translateY(-40px); } } 154 | 155 | .dcdialog.dcdialog-theme-default { 156 | padding-bottom: 160px; 157 | padding-top: 20px; } 158 | 159 | .dcdialog.dcdialog-theme-default.dcdialog-closing .dcdialog-content { 160 | -webkit-animation: dcdialog-flyout 0.5s; 161 | animation: dcdialog-flyout 0.5s; } 162 | 163 | .dcdialog.dcdialog-theme-default .dcdialog-content { 164 | -webkit-animation: dcdialog-flyin 0.5s; 165 | animation: dcdialog-flyin 0.5s; 166 | background: #f0f0f0; 167 | border-radius: 5px; 168 | color: #444; 169 | font-family: 'Helvetica',sans-serif; 170 | font-size: 1.1em; 171 | line-height: 1.5em; 172 | margin: 0 auto; 173 | max-width: 100%; 174 | padding: 1em; 175 | position: relative; 176 | width: 450px; } 177 | 178 | .dcdialog.dcdialog-theme-default .dcdialog-close { 179 | border-radius: 5px; 180 | cursor: pointer; 181 | position: absolute; 182 | right: 0; 183 | top: 0; } 184 | 185 | .dcdialog.dcdialog-theme-default .dcdialog-close:before { 186 | background: transparent; 187 | border-radius: 3px; 188 | color: #bbb; 189 | content: '\00D7'; 190 | font-size: 26px; 191 | font-weight: 400; 192 | height: 30px; 193 | line-height: 26px; 194 | position: absolute; 195 | right: 3px; 196 | text-align: center; 197 | top: 3px; 198 | width: 30px; } 199 | 200 | .dcdialog.dcdialog-theme-default .dcdialog-close:hover:before, 201 | .dcdialog.dcdialog-theme-default .dcdialog-close:active:before { 202 | color: #777; } 203 | 204 | .dcdialog.dcdialog-theme-default .dcdialog-message { 205 | margin-bottom: .5em; } 206 | 207 | .dcdialog.dcdialog-theme-default .dcdialog-input { 208 | margin-bottom: 1em; } 209 | 210 | .dcdialog.dcdialog-theme-default .dcdialog-input textarea, 211 | .dcdialog.dcdialog-theme-default .dcdialog-input input[type="text"], 212 | .dcdialog.dcdialog-theme-default .dcdialog-input input[type="password"], 213 | .dcdialog.dcdialog-theme-default .dcdialog-input input[type="email"], 214 | .dcdialog.dcdialog-theme-default .dcdialog-input input[type="url"] { 215 | background: #fff; 216 | border: 0; 217 | border-radius: 3px; 218 | font-family: inherit; 219 | font-size: inherit; 220 | font-weight: inherit; 221 | margin: 0 0 0.25em; 222 | min-height: 2.5em; 223 | padding: 0.25em 0.67em; 224 | width: 100%; } 225 | 226 | .dcdialog.dcdialog-theme-default .dcdialog-input textarea:focus, 227 | .dcdialog.dcdialog-theme-default .dcdialog-input input[type="text"]:focus, 228 | .dcdialog.dcdialog-theme-default .dcdialog-input input[type="password"]:focus, 229 | .dcdialog.dcdialog-theme-default .dcdialog-input input[type="email"]:focus, 230 | .dcdialog.dcdialog-theme-default .dcdialog-input input[type="url"]:focus { 231 | -webkit-box-shadow: inset 0 0 0 2px #8dbdf1; 232 | box-shadow: inset 0 0 0 2px #8dbdf1; 233 | outline: none; } 234 | 235 | .dcdialog.dcdialog-theme-default .dcdialog-buttons { 236 | *zoom: 1; } 237 | 238 | .dcdialog.dcdialog-theme-default .dcdialog-buttons:after { 239 | content: ''; 240 | display: table; 241 | clear: both; } 242 | 243 | .dcdialog.dcdialog-theme-default .dcdialog-button { 244 | border: 0; 245 | border-radius: 3px; 246 | cursor: pointer; 247 | float: right; 248 | font-family: inherit; 249 | font-size: .8em; 250 | letter-spacing: .1em; 251 | line-height: 1em; 252 | margin: 0 0 0 0.5em; 253 | padding: 0.75em 2em; 254 | text-transform: uppercase; } 255 | 256 | .dcdialog.dcdialog-theme-default .dcdialog-button:focus { 257 | -webkit-animation: dcdialog-pulse 1.1s infinite; 258 | animation: dcdialog-pulse 1.1s infinite; 259 | outline: none; } 260 | 261 | @media (max-width: 568px) { 262 | .dcdialog.dcdialog-theme-default .dcdialog-button:focus { 263 | -webkit-animation: none; 264 | animation: none; } } 265 | 266 | .dcdialog.dcdialog-theme-default .dcdialog-button.dcdialog-button-primary { 267 | background: #3288e6; 268 | color: #fff; } 269 | 270 | .dcdialog.dcdialog-theme-default .dcdialog-button.dcdialog-button-secondary { 271 | background: #e0e0e0; 272 | color: #777; } 273 | 274 | .hidden { 275 | display: none; } 276 | 277 | .splitbarV { 278 | position: absolute; 279 | top: 0px; 280 | left: 200px; 281 | width: 6px; 282 | height: 100%; 283 | z-index: 300; 284 | line-height: 0px; 285 | font-size: 0px; 286 | border-left: solid 1px #9cbdff; 287 | border-right: solid 1px #9cbdff; 288 | background: #cbe1fb url(img/panev.gif) 0% 50%; } 289 | 290 | .splitbuttonV { 291 | position: absolute; 292 | margin-top: -41px; 293 | top: 50%; 294 | left: -11px; 295 | height: 83px; 296 | width: 10px; 297 | background: transparent url(img/panevc.gif) 10px 50%; } 298 | 299 | .splitbuttonV.invert { 300 | position: absolute; 301 | left: 6px; 302 | background: transparent url(img/panevc.gif) 0px 50%; } 303 | 304 | .splitbarH { 305 | position: absolute; 306 | top: 200px; 307 | left: 0px; 308 | width: 100%; 309 | height: 6px; 310 | z-index: 300; 311 | text-align: left; 312 | line-height: 0px; 313 | font-size: 0px; 314 | border-top: solid 1px #9cbdff; 315 | border-bottom: solid 1px #9cbdff; 316 | background: #cbe1fb url(img/paneh.gif) 50% 0%; } 317 | 318 | .splitbuttonH { 319 | position: absolute; 320 | margin-left: -41px; 321 | top: -11px; 322 | left: 50%; 323 | height: 10px !important; 324 | width: 83px; 325 | background: transparent url(img/panehc.gif) 50% -10px; } 326 | 327 | .splitbuttonH.invert { 328 | position: absolute; 329 | top: 6px; 330 | background: transparent url(img/panehc.gif) 50% 0px; } 331 | 332 | .splitbarV.inactive, .splitbarH.inactive, .splitbuttonV.inactive, .splitbuttonH.inactive { 333 | -moz-opacity: .50; 334 | filter: alpha(opacity=50); 335 | opacity: .50; } 336 | -------------------------------------------------------------------------------- /demo/demo-choose-web-framework.coffee: -------------------------------------------------------------------------------- 1 | export default module.exports = -> 2 | onBlur = (event) -> 3 | comp.otherFramework = event.target.value 4 | comp.update() 5 | comp.textNode.focus() 6 | return 7 | 8 | frameworks = ['Domcom', 'jQuery', 'Angular', 'React', 'Backbone', 'Ember'] 9 | view = -> 10 | currentFrameWorks = frameworks.concat([comp.otherFramework || 'other']) 11 | frameworkLiItems = currentFrameWorks.map((item) -> 12 | onClick = -> 13 | comp.choice = item 14 | ['li', {onClick}, "#{item}"]) 15 | ['div', 16 | ['label', 'Please choose: '], 17 | ['ol', {}, frameworkLiItems...], 18 | ['div', "You perfer ", comp.choice, "."] 19 | ['label', 'add some others: '], 20 | ['text', {onBlur, value:comp.otherFramework, key:'other-framework', ref:((el) -> comp.textNode = el), keepid:1}] 21 | ] 22 | 23 | comp = dc({view, choice:'Domcom'}) 24 | 25 | 26 | -------------------------------------------------------------------------------- /demo/demo-controls.coffee: -------------------------------------------------------------------------------- 1 | export default module.exports = -> 2 | view = ['div', ['checkbox','a'], ['text', 'a'],['checkbox', 'b'], ['text', 'b']] 3 | return dc({view, a:true, b:true}) -------------------------------------------------------------------------------- /demo/demo-counter.coffee: -------------------------------------------------------------------------------- 1 | export default module.exports = -> 2 | timer = null 3 | 4 | view = -> 5 | comp = this 6 | start = => 7 | startCounter() 8 | return 9 | stop = => 10 | stopCounter() 11 | reset = => 12 | stopCounter() 13 | comp.count = 0 14 | 15 | ['div', 16 | ['p', this.count], 17 | ['p', {onClick: stop, keepid:101}, 'stop'], 18 | ['p', {onClick: reset, keepid:102}, 'reset'], 19 | ['p', {onClick: start, keepid:103}, 'start'] 20 | ] 21 | comp = dc({view, count:0}) 22 | startCounter = -> 23 | timer = setInterval (-> comp.count++), 300 24 | return 25 | stopCounter = -> 26 | clearInterval timer 27 | 28 | comp.on 'mounted', -> 29 | startCounter() 30 | comp.on 'unmounting', -> 31 | stopCounter() 32 | 33 | 34 | return comp 35 | -------------------------------------------------------------------------------- /demo/demo-debug.coffee: -------------------------------------------------------------------------------- 1 | exports = {} 2 | 3 | exports.demoEachPush = -> 4 | list = [1, 2] 5 | view = ['div', ['div', this.list.map((item) => ['p', item])], 'some other thing'] 6 | comp = dc({view, list}) 7 | comp.mount() 8 | lst.push 3 9 | comp.update() 10 | 11 | exports.demoIfEach = -> 12 | view = -> 13 | if this.showing 14 | this.list.map (item) -> ['div', {}, item] 15 | else 16 | null 17 | comp = {view, list:[1, 2]} 18 | comp.mount() 19 | comp.showing = false 20 | comp.showing = true 21 | comp 22 | 23 | exports.demoModelOnMultipleInput = -> 24 | view = -> 25 | ['div', ['text', {'#':[[dc.model,'x']]}], ['text', {'#':[[dc.model,'x']]}]] 26 | comp = dc({view, x:'input some text'}) 27 | 28 | export default exports -------------------------------------------------------------------------------- /demo/demo-each.coffee: -------------------------------------------------------------------------------- 1 | export default module.exports= -> 2 | list = [1, 2, 3, 4, 5, 6] 3 | i = 7 4 | onClick = -> 5 | list.push i++ 6 | comp.update() 7 | view = -> ['div', {onClick}, 'click to append: ', this.list.join(' ')] 8 | comp = dc({view, list}) 9 | 10 | -------------------------------------------------------------------------------- /demo/demo-function-lead-item.coffee: -------------------------------------------------------------------------------- 1 | if_ = (test, then_, else_) -> 2 | if test 3 | then_ 4 | else 5 | else_ 6 | 7 | 8 | export default module.exports = -> 9 | view = -> ['div', 10 | ['text', 'x'], 11 | [if_, !(this.x*1), ['div', 'It is 0 or NaN.'], ['div', 'it is other number']]] 12 | dc({view, x:1}) 13 | -------------------------------------------------------------------------------- /demo/demo-show-hide.coffee: -------------------------------------------------------------------------------- 1 | export default module.exports = -> 2 | view = (data) -> 3 | if this.display 4 | display = 'block' 5 | else 6 | display = 'none' 7 | onClick = () => 8 | this.display = !this.display 9 | 10 | ['div', 11 | ['div', { onClick}, 'click to show or hide by changing style.display'], 12 | ['p', { style:{display}}, 'this is the controlled content'] 13 | ] 14 | comp = dc({view, display:true}) 15 | return comp 16 | 17 | -------------------------------------------------------------------------------- /demo/demo-sum.coffee: -------------------------------------------------------------------------------- 1 | export default module.exports = () -> 2 | 3 | data = { a: 1, b: 2 } 4 | view = (data) -> 5 | props1 = 6 | focusid:1 7 | value: data.a, 8 | onChange:(event) -> 9 | data.a = event.target.value*1 10 | comp.update() 11 | 12 | props2 = 13 | focusid:2 14 | value: data.b, 15 | onChange: (event) -> 16 | data.b = event.target.value*1 17 | comp.update() 18 | 19 | return ['div',{key:0} 20 | ['text', props1], 21 | ['text', props2], 22 | ['p', data.a + data.b] 23 | ] 24 | 25 | comp = dc({data, view}) 26 | -------------------------------------------------------------------------------- /demo/demo-text-model.coffee: -------------------------------------------------------------------------------- 1 | export default module.exports = -> 2 | view = -> ['div', ['text', {$model:'a', key:1, ref:(el)->comp.textInput = el}], ['p', {}, this.a]] 3 | comp = dc({view, a:'hello'}) 4 | comp.on 'updated', -> 5 | comp.textInput.focus() 6 | return 7 | -------------------------------------------------------------------------------- /demo/index-dist.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Tiiji demo index 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /demo/index.coffee: -------------------------------------------------------------------------------- 1 | dc.addReactProxy window.React, window.ReactDOM, window.React.Component 2 | 3 | {runDemo, demoMap} = require './util' 4 | 5 | window.onload = -> 6 | # demo = require('./demo-text-model') 7 | # comp = demo() 8 | # comp.mount('#demo') 9 | # return 10 | # comp = demoMap["show hide"]() 11 | # comp = demoMap["counter"]() 12 | # comp = demoMap["dialog"]() 13 | # comp = demoMap["event"]() 14 | # comp = demoMap["controls"]() 15 | # comp = demoMap["if"]() 16 | # comp = demoMap["each1"]() 17 | # comp = demoMap["each2"]() 18 | # comp = demoMap["each3"]() 19 | # comp = demoMap["each4"]() 20 | # comp = demoMap["switch 1 2 3 4"]() 21 | # comp = demoMap["splitter"]() 22 | # comp = demoMap["sum"]() 23 | # comp = demoMap["text model"]() 24 | # comp = demoMap["auto width edit"]() 25 | # comp = demoMap["mount/unmount"]() 26 | # comp = chooseFramework() 27 | # comp.mount() 28 | 29 | # demoEachPush() 30 | # demoIfEach() 31 | # demoModelOnMultipleInput() 32 | 33 | runDemo(demoMap, 'choose web framework', '#demo') -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Domcom demo index 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /demo/todomvc-dist.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | domcom.js -- TodoMVC 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /demo/todomvc.coffee: -------------------------------------------------------------------------------- 1 | dc.addReactProxy window.React, window.ReactDOM, window.React.Component 2 | 3 | ####################################################################################################################### 4 | # store 5 | 6 | window.fetch = -> JSON.parse localStorage.getItem('todoApp') || '[]' 7 | window.save = (todos) -> localStorage.setItem('todoApp', JSON.stringify(todos)) 8 | 9 | ####################################################################################################################### 10 | # model 11 | # [ { title: string, completed: boolean } ... ] 12 | window.todos = [] 13 | window.todos = fetch() 14 | 15 | ####################################################################################################################### 16 | # controller 17 | 18 | viewStatusHash = null 19 | editingTodo = {title:'', completed:false} 20 | originalTodo = null 21 | reverted = null 22 | saving = false 23 | 24 | window.getTodos = -> 25 | if viewStatusHash=='active' 26 | todos.filter (todo) -> todo && !todo.completed 27 | else if viewStatusHash=='completed' 28 | todos.filter (todo) -> todo && todo.completed 29 | else 30 | todos 31 | 32 | remainingCount = -> todos.filter((todo) -> !todo.completed).length 33 | completedCount = -> todos.length - remainingCount() 34 | allChecked = -> !remainingCount() 35 | 36 | pluralize = (test, item) -> 37 | if test>1 38 | item+'s' 39 | else 40 | item 41 | 42 | toggleCompleted = (todo) -> 43 | todo.completed = !todo.completed 44 | save todos 45 | app.update() 46 | 47 | markAll = -> 48 | if allChecked() then completed = false 49 | else completed = true 50 | 51 | valid = true 52 | for todo in todos 53 | if todo.completed!=completed 54 | todo.completed = completed 55 | valid = false 56 | 57 | if !valid 58 | save(todos) 59 | app.update() 60 | 61 | editTodo = (todo) -> 62 | editingTodo = todo 63 | originalTodo = Object.assign {}, todo 64 | app.update() 65 | 66 | removeTodo = (todo) -> 67 | index = todos.indexOf todo 68 | todos.splice index, 1 69 | save todos 70 | app.update() 71 | 72 | clearCompletedTodos = -> 73 | valid = true 74 | 75 | i = todos.length - 1 76 | while i>=0 77 | if todos[i].completed 78 | todos.splice i, 1 79 | valid = false 80 | i-- 81 | 82 | if !valid 83 | save todos 84 | app.update() 85 | 86 | ####################################################################################################################### 87 | # view 88 | 89 | 90 | todoHeader = -> 91 | onKeyUp = (event) -> 92 | console.log('onBlur todos: ', todos) 93 | keyCode = event.keyCode || event.which 94 | if keyCode==27 95 | editingTodo = {title: '', completed:false} 96 | else if keyCode == 13 97 | editingTodo.title = value = event.target.value 98 | if !value 99 | return 100 | else 101 | todos.push(editingTodo) 102 | editingTodo = {title:'', completed:false} 103 | save todos 104 | app.update() 105 | onBlur = (event) -> 106 | console.log('onBlur todos: ', todos) 107 | debugger 108 | node = event.target 109 | value = node.value 110 | editingTodo.title = value 111 | if !value 112 | return 113 | else 114 | todos.push(editingTodo) 115 | editingTodo = {title:'', completed:false} 116 | save todos 117 | app.update() 118 | return 119 | onChange = (event) -> 120 | node = event.target 121 | value = node.value 122 | editingTodo.title = value 123 | app.update() 124 | return 125 | 126 | ['header#header',{key:1} 127 | ['h1', "todos"] 128 | ['text#new-todo', {value:editingTodo.title, onChange, onBlur, onKeyUp, key:2, focusid:1}] 129 | 130 | ] 131 | 132 | 133 | todoEditArea = -> 134 | todos = getTodos() 135 | todoItems = todos.map (todo, index) -> 136 | onChange = (event) -> 137 | todo.title = event.target.value 138 | app.update() 139 | onBlur = (event) -> 140 | todo.title = event.target.value 141 | save(todos) 142 | editingTodo = {} 143 | app.update(); 144 | onFocus = -> 145 | todo = editingTodo 146 | onKeyUp = (event) -> 147 | keyCode = event.keyCode || event.which 148 | if keyCode==27 149 | todos[todos.indexOf(todo)] = editingTodo = originalTodo 150 | else if keyCode == 13 151 | save(todos) 152 | editingTodo = {title:'', completed:false} 153 | app.update() 154 | onToggle = -> 155 | toggleCompleted(todo) 156 | if_ = (x, y, z) -> 157 | if x 158 | y 159 | else 160 | z 161 | ['li', {className: { completed: todo.completed, editing: todo==editingTodo, key:5},onDoubleClick:( -> editTodo(todo) )}, 162 | ['div#view', 163 | ['checkbox.toggle', {checked: todo.completed, onChange:onToggle, key:1000+index}], 164 | [if_, todo!=editingTodo, 165 | ['label', todo.title], 166 | ['text.edit', { trim:'false', value:todo.title, onBlur, onChange, onFocus, onKeyUp, focusid:100+index}]] 167 | ['button.destroy##float:right', {onClick:(-> removeTodo(todo))}, 'x']]] 168 | 169 | ['section#main', 170 | ['checkbox.toggle#toggle-all', { key:6, checked: !!allChecked(), onChange: markAll}] 171 | ['label##display:inline-block;', {htmlFor: "toggle-all"}, "Mark all as complete"] 172 | ["ul#todo-list", todoItems...], 173 | ["footer#footer", {$show:!!todos.length}, 174 | ["span#todo-count", ['strong',remainingCount()], pluralize(remainingCount(), ' item'), ' left'], 175 | ["ul#filters", 176 | ['li', ['a', {className: {selected: viewStatusHash != 'active' && viewStatusHash != 'completed'}, href: "#/all"}, "All"]] 177 | ['li', ['a', {className: {selected: viewStatusHash == 'active'}, href: "#/active"}, "Active"]] 178 | ['li', ['a', {className: {selected: viewStatusHash == 'completed'}, href: "#/completed"}, "Completed"]]]] 179 | 180 | ['button#clear-completed', {onClick: clearCompletedTodos, $show: !!completedCount()}, 181 | "Clear completed: "+completedCount()]] 182 | 183 | todoFooter = ['footer#info', {key:100}, 184 | ['p', "Double-click to edit a todo"] 185 | ['p', 'Created by ', 186 | ['a', {href:"http://github.com/taijiweb/domcom"}, 187 | 'Caoxingming(Tiijizhenren, simeon.chaos@gmail.com)']] 188 | ['p', "Part of ", 189 | ['a', {href:"http://todomvc.com"}, 190 | " TodoMVC"]]] 191 | 192 | view = -> 193 | ['section#todoapp', {key:0}, 194 | todoHeader() 195 | todoEditArea() 196 | todoFooter 197 | ] 198 | app = dc({view}) 199 | 200 | window.updateHash = -> 201 | locationHash = document.location.hash 202 | if locationHash.indexOf('/') >= 0 203 | viewStatusHash = locationHash.split('/')[1] || '' 204 | else 205 | viewStatusHash = locationHash 206 | 207 | ####################################################################################################################### 208 | # run the app 209 | 210 | window.runTodoMvc = -> 211 | updateHash() 212 | app.mount('#todo-app') 213 | 214 | window.addEventListener 'hashchange', -> 215 | updateHash() 216 | app.update() 217 | -------------------------------------------------------------------------------- /demo/todomvc.css: -------------------------------------------------------------------------------- 1 | .edit { 2 | display: inline-block; 3 | } 4 | 5 | .edit { 6 | width: 90%; 7 | } -------------------------------------------------------------------------------- /demo/todomvc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | domcom.js -- TodoMVC 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | -------------------------------------------------------------------------------- /demo/util.coffee: -------------------------------------------------------------------------------- 1 | # domcom demo 2 | 3 | eachDemo = require './demo-each' 4 | import chooseFramework from './demo-choose-web-framework' 5 | 6 | {demoEachPush, demoIfEach, demoModelOnMultipleInput} = require './demo-debug' 7 | 8 | export default module.exports = exports = {} 9 | 10 | exports.demoMap = 11 | 'choose web framework':chooseFramework, 12 | "show hide": require('./demo-show-hide'), 13 | counter: require('./demo-counter') 14 | controls: require('./demo-controls'), 15 | 'function lead item': require('./demo-function-lead-item'), 16 | sum: require('./demo-sum'), 17 | 'text model': require('./demo-text-model') 18 | 19 | exports.makeDemoComponent = makeDemoComponent = (demoMap, initItem) -> 20 | componentsMap = {} 21 | for key, comp of demoMap 22 | if typeof comp == 'function' 23 | componentsMap[key] = comp() 24 | else 25 | componentsMap[key] = comp 26 | view = -> 27 | ['div', 28 | ['select', {$options:Object.keys(demoMap), $model:'select'}], 29 | ['div', componentsMap[comp.select]]] 30 | 31 | comp = dc({view, select:initItem}) 32 | 33 | exports.runDemo = (demoMap, initItem, element) -> 34 | comp = makeDemoComponent(demoMap, initItem) 35 | comp.mount(element) -------------------------------------------------------------------------------- /doc/ concepts and principles.md: -------------------------------------------------------------------------------- 1 | # Domcom framework basic concepts and principles 2 | The principle of the Domcom framework is very simple, and it is clear in one sentence: the Domcom component itself supports the React element in a js-friendly compact format (nested array form) through its view function, and then uses its React proxy component class ReactProxy in it. This nested array is converted to the actual React element in the render method. that is it. For more details, you can take a look at the following further analysis of the basic concepts involved. 3 | 4 | # basic concept 5 | * **Components** 6 | 7 | TComponent is the core concept of the Domcom skeleton, it is the proxy used by the domcom framework to manage React elements. Each component is constructed from a config object. Only the data and view in the fonfig object have special effects. The most important is the view member (which can be the actual view data or the function that generates the view). Then, through the React component class ReactProxy, a react element is generated. When the React element is mounted, the ReactProxy instance pointer this is provided to the proxy member field of the Domcom component. Domcom uses the instance pointer to manage the Dom update of the React element through the update method. (by calling the component.proxy.setState method) and remove. 8 | 9 | * **ReactProxy** 10 | 11 | Each Domcom component creates a React element via ReactProxy. ReactProxy generates a React element structure based on the view field of the corresponding Domcom component. 12 | 13 | * **High-order virtual Dom** 14 | 15 | React invented the concept and technology of virtual Dom, and Domcom carried forward the concept and technology. If the virtual Dom is a pre-declared Dom hierarchy in the form of some kind of js, in order to manage optimization. If we consider the native Dom as a first-order Dom, React's virtual Dom can be thought of as a second-order Dom, because the api that is used directly to create the React element is cumbersome and inconvenient to read and write. So there is a syntax for jsx that returns to the xhtml format and hybridizes with js. Jsx can also be considered as a third-order high-order virtual Dom. The nested array notation provided by Domcom is just another third-order virtual Dom. This format of virtual Dom is easy to read and write, js friendly, no need for toolchain support, and has many advantages. 16 | 17 | The above has clearly and completely introduced Domcom's concepts and principles. People who have further concerns about technical details can read the source code directly. Domcom's source code is very simple, with a total of only seven files, about 500 lines of code, the more critical code is mainly in [Component.coffee](https://github.com/taijiweb/domcom/blob/master/src/Component. Coffee), [react-proxy.coffee](https://github.com/taijiweb/domcom/blob/master/src/react-proxy.coffee), [dc-util.coffee](https://github. Com/taijiweb/domcom/blob/master/src/dc-util.coffee) Of these three files, there are only a hundred lines of CoffeeScript, which are very concise and intuitive to implement. Welcome to read. -------------------------------------------------------------------------------- /doc/Chinese/API参考.md: -------------------------------------------------------------------------------- 1 | # Domcom API 参考文档 2 | 3 | ************************************************************************ 4 | 5 | ## 使用Domcom 6 | ### 获取Domcom 7 | `npm install --save domcom` 8 | `git clone https://www.github.com/taijiweb/domcom` 9 | 下载:[github版本](https://github.com/taijiweb/domcom/releases) 10 | cdn: 感谢cdn.jsdelivr.net 提供cdn链接(替换x.y.z为实际版本号) 11 | 12 | http://cdn.jsdelivr.net/domcom/x.y.z/domcom.min.js 13 | 14 | ### 在页面中设置Domcom 15 | 先要添加React和ReactDom链接。 16 | 17 | 18 | 19 | 20 | 或 21 | 22 | 23 | 24 | 25 | 根据开发和应用需要从安装或下载的文件夹中选择domcom/dist/下的适当文件,向html页面添加script标签: 26 | > 开发版本:` 16 | 17 | 18 | 或 19 | 20 | 21 | 22 | 23 | 然后添加Domcom script标签: 24 | 25 | * 开发版本: ` 16 | 17 | 18 | or 19 | 20 | 21 | 22 | 23 | Then add the Domcom script tag: 24 | 25 | * Development version: ` 15 | 16 | 17 |
clear demo
18 |
clear log
19 |
20 | 21 |
22 | 23 |
24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /test/mocha-runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Mocha Test Runner 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
clear demo
18 |
clear log
19 |
20 | 21 |
22 |
23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /test/mocha-test.css: -------------------------------------------------------------------------------- 1 | #demo { 2 | border: 1px solid #000000; 3 | width: 100%; 4 | } 5 | 6 | #debug-log { 7 | position: fixed; 8 | top: 60px; 9 | left: 800px; 10 | overflow: scroll; 11 | width: 550px; 12 | height: 500px; 13 | } 14 | 15 | #clear-demo { 16 | position: fixed; 17 | top: 20px; 18 | left: 600px; 19 | padding: 10px; 20 | border: 1px solid blue; 21 | background-color: lightgray; 22 | } 23 | 24 | #clear-log { 25 | position: fixed; 26 | top: 20px; 27 | left: 800px; 28 | padding: 10px; 29 | border: 1px solid blue; 30 | background-color: lightgray; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /test/react-vue-components/HelloReact.coffee: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react' 2 | 3 | export default module.exports = class HelloReact extends Component 4 | render: -> 5 | return React.createElement('div', {}, ['hello react in vue ', this.props.who]) -------------------------------------------------------------------------------- /test/react-vue-components/HelloVue.coffee: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export default module.exports = Vue.component('hello-vue', { 4 | props: ['who'], 5 | render: (h) -> 6 | return h('div', {}, ['hello vue ', this.who]) 7 | }) -------------------------------------------------------------------------------- /test/test-antd.coffee: -------------------------------------------------------------------------------- 1 | {expect, iit, idescribe, nit, ndescribe} = require 'bdd-test-helper' 2 | 3 | {normalizeItem, normalizeDomElement} = require 'dc-util' 4 | 5 | import React, {Component} from 'react' 6 | import ReactDom from 'react-dom' 7 | dc.addReactProxy React, ReactDom, Component 8 | 9 | import Chip from '@material-ui/core/Chip' 10 | 11 | import { Button } from 'antd' 12 | 13 | describe "test-antd", -> 14 | beforeEach -> 15 | demoNode = normalizeDomElement('#demo') 16 | if demoNode.childNodes.length 17 | node = demoNode.childNodes[0] 18 | demoNode.removeChild(node) 19 | 20 | # tell React do not warn about this 21 | demoNode._reactRootContainer = undefined 22 | return 23 | 24 | describe 'mount some material-ui dc components', -> 25 | it 'simple Button', -> 26 | view = ['div' 27 | [Button, {type:"primary"},'Default'], 28 | [Button, 'Default'], 29 | [Button, {type:"dashed"},'dashed'], 30 | [Button, {type:"danger"},'danger'] 31 | ] 32 | 33 | comp = dc {view} 34 | comp.mount('#demo') -------------------------------------------------------------------------------- /test/test-directive.coffee: -------------------------------------------------------------------------------- 1 | {expect, iit, idescribe, nit, ndescribe} = require 'bdd-test-helper' 2 | 3 | {normalizeItem, normalizeDomElement} = require 'dc-util' 4 | 5 | import React, {Component} from 'react' 6 | import ReactDom from 'react-dom' 7 | dc.addReactProxy React, ReactDom, Component 8 | 9 | import Button from '@material-ui/core/Button' 10 | 11 | describe "test-directive", -> 12 | beforeEach -> 13 | demoNode = normalizeDomElement('#demo') 14 | if demoNode.childNodes.length 15 | node = demoNode.childNodes[0] 16 | demoNode.removeChild(node) 17 | 18 | # tell React do not warn about this 19 | demoNode._reactRootContainer = undefined 20 | return 21 | 22 | describe 'model directive 1', -> 23 | it 'should process model directive', -> 24 | view = -> 25 | [['text', {$model:'message'}], ['p', @message]] 26 | comp = dc({view, message:'hello'}) 27 | comp.mount('#demo') 28 | 29 | it 'should process model directive 2', -> 30 | view = -> 31 | ['div', ['text', {$model:'message'}], ['p', this.message]] 32 | comp = dc({view, message:'hello'}) 33 | comp.mount('#demo') 34 | 35 | it 'should process model directive 3', -> 36 | view = -> 37 | ['div', ['text', 'message'], ['p', this.message]] 38 | comp = dc({view, message:'hello'}) 39 | comp.mount('#demo') 40 | 41 | it 'should process view event without model directive', -> 42 | view = () -> 43 | onChange = (event) => 44 | comp.message = event.target.value 45 | ['div', ['text', {value: this.message, onChange}], ['p', this.message]] 46 | message = 'hello' 47 | comp = dc({view, message}) 48 | comp.mount('#demo') 49 | -------------------------------------------------------------------------------- /test/test-event.coffee: -------------------------------------------------------------------------------- 1 | {expect, iit, idescribe, nit, ndescribe} = require 'bdd-test-helper' 2 | 3 | {normalizeItem, normalizeDomElement} = require 'dc-util' 4 | 5 | import React, {Component} from 'react' 6 | import ReactDom from 'react-dom' 7 | dc.addReactProxy React, ReactDom, Component 8 | 9 | describe "test events", -> 10 | beforeEach -> 11 | demoNode = normalizeDomElement('#demo') 12 | if demoNode.childNodes.length 13 | node = demoNode.childNodes[0] 14 | demoNode.removeChild(node) 15 | 16 | # tell React do not warn about this 17 | demoNode._reactRootContainer = undefined 18 | return 19 | 20 | it 'should process onClick', -> 21 | data = {message:"click me!"} 22 | onClick = -> 23 | data.message = "you clicked!" 24 | dc.update() 25 | view = (data) -> ['div', {onClick}, data.message] 26 | embedded = dc({data, view}) 27 | comp = dc({view:embedded}) 28 | comp.mount('#demo') -------------------------------------------------------------------------------- /test/test-material-ui.coffee: -------------------------------------------------------------------------------- 1 | {expect, iit, idescribe, nit, ndescribe} = require 'bdd-test-helper' 2 | 3 | {normalizeItem, normalizeDomElement} = require 'dc-util' 4 | 5 | import React, {Component} from 'react' 6 | import ReactDom from 'react-dom' 7 | dc.addReactProxy React, ReactDom, Component 8 | 9 | 10 | import Button from '@material-ui/core/Button' 11 | import Avatar from '@material-ui/core/Avatar' 12 | import List from '@material-ui/core/List' 13 | import ListItem from '@material-ui/core/ListItem' 14 | import ListItemAvatar from '@material-ui/core/ListItemAvatar' 15 | import ListItemText from '@material-ui/core/ListItemText' 16 | import DialogTitle from '@material-ui/core/DialogTitle' 17 | import Dialog from '@material-ui/core/Dialog' 18 | import Typography from '@material-ui/core/Typography' 19 | import blue from '@material-ui/core/colors/blue' 20 | import PersonIcon from '@material-ui/icons/Person' 21 | import AddIcon from '@material-ui/icons/Add' 22 | import AppBar from '@material-ui/core/AppBar' 23 | import Toolbar from '@material-ui/core/Toolbar' 24 | import IconButton from '@material-ui/core/IconButton' 25 | import CloseIcon from '@material-ui/icons/Close' 26 | import Divider from '@material-ui/core/Divider' 27 | import Slide from '@material-ui/core/Slide' 28 | 29 | window.__MUI_USE_NEXT_TYPOGRAPHY_VARIANTS__ = true 30 | 31 | describe "test-material-ui", -> 32 | beforeEach -> 33 | demoNode = normalizeDomElement('#demo') 34 | if demoNode.childNodes.length 35 | node = demoNode.childNodes[0] 36 | demoNode.removeChild(node) 37 | 38 | # tell React do not warn about this 39 | demoNode._reactRootContainer = undefined 40 | return 41 | 42 | describe 'mount some material-ui dc components', -> 43 | it 'simple material-ui Button', -> 44 | view = ['div' 45 | [Button, {variant:"text", color:"primary"},'primary'], 46 | [Button, 'Default'], 47 | [Button, {variant:"outlined", color:"secondary", disabled:true},'secondary'], 48 | [Button, {variant:"contained", color:"inherit"},'danger'] 49 | ] 50 | comp = dc {view} 51 | comp.mount('#demo') 52 | 53 | it 'test a dialog', -> 54 | data = { 55 | emails:['x1@y.z', 'x2@y.z', 'x3@y.z'], 56 | open:true, 57 | handleListItemClick: (message)-> 58 | alert 'handleListItemClick: ' + message 59 | data.open = false 60 | dc.update() 61 | handleClose: -> 62 | data.open = false 63 | dc.update() 64 | } 65 | view = (data) -> 66 | [Dialog, {onClose:data.handleClose, 'aria-labelledby':"simple-dialog-title", open:data.open, className:''}, 67 | [DialogTitle, "#simple-dialog-title", {key:++dc.dcid}, "Set backup account"], 68 | ['div', {key:++dc.dcid} 69 | [List,{className:'', key:++dc.dcid} 70 | data.emails.map((email) => 71 | [ListItem, {button:true, onClick:(() => data.handleListItemClick(email)), key:email, className:''}, 72 | #[ListItemAvatar, [Avatar, [PersonIcon]]], 73 | [ListItemText, {primary:email, className:'', key:email}, email] 74 | ]), 75 | [ListItem, {button:true, key:dc.dcid++, onClick:() => data.handleListItemClick('addAccount')}, 'add account']]]] 76 | comp = dc({data, view}) 77 | comp.mount('#demo') 78 | 79 | 80 | it 'test a dialog 2', -> 81 | Transition = (props) -> 82 | React.createElement(Slide, {direction:"up", props...}) 83 | data = 84 | emails: ['x1@y.z', 'x2@y.z', 'x3@y.z'], 85 | open:true, 86 | handleListItemClick: (message)-> 87 | alert 'handleListItemClick: ' + message 88 | data.open = false 89 | dc.update() 90 | 91 | handleClickOpen: -> 92 | data.open = true 93 | dc.update() 94 | 95 | close: -> 96 | data.open = false 97 | dc.update() 98 | 99 | view = (data) -> 100 | ['div', 101 | [Button, {onClick:data.handleClickOpen}, "Open full-screen dialog"], 102 | [Dialog, {fullScreen:true, open:data.open, onClose:data.close, TransitionComponent:Transition}, 103 | [AppBar, '.appBar', 104 | [Toolbar, 105 | [IconButton, {color:"inherit", onClick:data.close, 'aria-label':"Close"}, [CloseIcon]], 106 | [Typography, {variant:"h6", color:"inherit", className:'.flex'}, 'Sound'] 107 | [Button, {color:"inherit", onClick:data.close}, "save"] 108 | ]], 109 | [List, 110 | [ListItem, {button:true}, 111 | [ListItemText, {primary:"Phone ringtone", secondary:"Titania"}]], 112 | [Divider] 113 | [ListItem, {button:true}, 114 | [ListItemText, {primary:"Default notification ringtone", secondary:"Tethys"}]]]]] 115 | comp = dc({data, view}) 116 | comp.mount('#demo') -------------------------------------------------------------------------------- /test/test-new-dc.coffee: -------------------------------------------------------------------------------- 1 | {expect, iit, idescribe, nit, ndescribe} = require 'bdd-test-helper' 2 | 3 | {normalizeItem, normalizeDomElement} = require 'dc-util' 4 | 5 | import React, {Component} from 'react' 6 | import ReactDom from 'react-dom' 7 | dc.addReactProxy React, ReactDom, Component 8 | 9 | import Button from '@material-ui/core/Button' 10 | 11 | describe "test-new-dc", -> 12 | beforeEach -> 13 | demoNode = normalizeDomElement('#demo') 14 | if demoNode.childNodes.length 15 | node = demoNode.childNodes[0] 16 | demoNode.removeChild(node) 17 | 18 | # tell React do not warn about this 19 | demoNode._reactRootContainer = undefined 20 | return 21 | 22 | describe 'mount simple dc components', -> 23 | it 'should dc generate a component', -> 24 | comp = dc() 25 | expect(comp instanceof dc.Component).to.be.true 26 | 27 | it ' dc should check fields', -> 28 | expect(-> dc {dcid:'should error'}).to.throw dc.DomcomError 29 | 30 | it 'simple data view', -> 31 | data = {x:1, y:2} 32 | view = (data) -> 33 | {x, y} = data 34 | return ['div', ['div', x], ['div', y]] 35 | comp = dc {data, view} 36 | 37 | it 'config.view should work 1', -> 38 | view = -> ['div', {}, 'hello domcom mvc'] 39 | comp = dc({view}) 40 | comp.mount('#demo') 41 | node = document.querySelector('#demo') 42 | expect(node.innerHTML).to.equal '
hello domcom mvc
' 43 | 44 | it 'config.view should work 2', -> 45 | view = ['div', 'hello domcom mvc'] 46 | comp = dc({view}) 47 | comp.mount('#demo') 48 | 49 | it 'normalizeItem should work', -> 50 | view = ['div', 'hello domcom mvc'] 51 | comp = dc({view}) 52 | item = normalizeItem(comp.view) 53 | s = JSON.stringify(item) 54 | expect(s).to.equal '["div",{},["hello domcom mvc"]]' 55 | 56 | it 'class in both tag string and props', -> 57 | view = ['div.btn', {classes:"active"}, 'hello domcom mvc'] 58 | comp = dc({view}) 59 | item = normalizeItem(comp.view) 60 | s = JSON.stringify(item) 61 | expect(s).to.equal '["div",{"className":"btn active"},["hello domcom mvc"]]' 62 | 63 | it 'style in both tag string and props 1', -> 64 | view = ['div##width:100;', {css:"height:200px"}, 'hello domcom mvc'] 65 | item = normalizeItem(view) 66 | s = JSON.stringify(item) 67 | expect(s).to.equal '["div",{"style":{"width":"100","height":"200px"}},["hello domcom mvc"]]' 68 | 69 | it 'style and css in both tag string and props 2', -> 70 | red = 'red' 71 | view = ['div##width:100;', {css:"height:200px", style:{backgroundColor:red}}, 'hello domcom mvc'] 72 | item = normalizeItem(view) 73 | s = JSON.stringify(item) 74 | expect(s).to.equal '["div",{"style":{"width":"100","height":"200px","backgroundColor":"red"}},["hello domcom mvc"]]' 75 | 76 | it 'camelCase style and css in both tag string and props 1', -> 77 | red = 'red' 78 | view = ['div##width:100;', {css:"height:200px", style:{'background-color':red}}, 'hello domcom mvc'] 79 | comp = dc({view}) 80 | item = normalizeItem(comp.view) 81 | s = JSON.stringify(item) 82 | expect(s).to.equal '["div",{"style":{"width":"100","height":"200px","backgroundColor":"red"}},["hello domcom mvc"]]' 83 | 84 | it 'multiple props 1', -> 85 | red = 'red' 86 | view = ['div##width:100;', {css:"height:200px"}, {'background-color':red}, 'hello domcom mvc'] 87 | comp = dc({view}) 88 | item = normalizeItem(comp.view) 89 | s = JSON.stringify(item) 90 | expect(s).to.equal '["div",{"backgroundColor":"red","style":{"width":"100","height":"200px"}},["hello domcom mvc"]]' 91 | 92 | it 'classname with true value', -> 93 | red = 'red' 94 | active = true 95 | view = ['div##width:100;', {classes:{active}}, {'background-color':red}, 'hello domcom mvc'] 96 | comp = dc({view}) 97 | item = normalizeItem(comp.view) 98 | s = JSON.stringify(item) 99 | expect(s).to.equal '["div",{"backgroundColor":"red","className":"active","style":{"width":"100"}},["hello domcom mvc"]]' 100 | 101 | it 'classname with falsy value', -> 102 | red = 'red' 103 | active = false 104 | view = ['div##width:100;', {classes:{active}}, {'background-color':red}, 'hello domcom mvc'] 105 | comp = dc({view}) 106 | item = normalizeItem(comp.view) 107 | s = JSON.stringify(item) 108 | expect(s).to.equal '["div",{"backgroundColor":"red","style":{"width":"100"}},["hello domcom mvc"]]' 109 | 110 | it 'tagstr follow ReactClass', -> 111 | red = 'red' 112 | active = false 113 | view = [Button, '##width:100;', {classes:{active}}, {'background-color':red}, 'hello domcom mvc'] 114 | comp = dc({view}) 115 | item = normalizeItem(comp.view) 116 | s = JSON.stringify(item[1...]) 117 | # will not camelcase in props in ReactClass element 118 | expect(s).to.equal '[{"background-color":"red","style":{"width":"100"}},["hello domcom mvc"]]' 119 | 120 | it 'should work on view function', -> 121 | view = (data) -> ['div', 'hello', data] 122 | comp = dc({data:" data", view}) 123 | view = comp.getView() 124 | item = normalizeItem(view) 125 | s = JSON.stringify(item) 126 | expect(s).to.equal '["div",{},["hello"," data"]]' 127 | comp.mount('#demo') 128 | 129 | it 'view function should work on data', -> 130 | view = (data) -> ['div', 'hello', data] 131 | comp = dc({view}) 132 | comp.mount('#demo') 133 | node = document.querySelector('#demo') 134 | expect(node.innerHTML).to.equal '
hello
' 135 | 136 | it 'tag.classes#id should work', -> 137 | view = (data) -> ['div.btn#button1', 'hello', data] 138 | comp = dc({view}) 139 | comp.mount('#demo') 140 | node = document.querySelector('#demo') 141 | expect(node.innerHTML).to.equal '
hello
' 142 | 143 | it 'tag.classes#id::css should work 1', -> 144 | view = (data) -> ['div.btn#button1##width:20px;', 'hello', data] 145 | comp = dc({view}) 146 | comp.mount('#demo') 147 | node = document.querySelector('#demo') 148 | expect(node.innerHTML).to.equal '
hello
' 149 | 150 | it 'tag.classes#id::css should work 2', -> 151 | view = (data) -> ['.btn#button1##width:20px;color:red', 'hello', data] 152 | comp = dc({view}) 153 | comp.mount('#demo') 154 | node = document.querySelector('#demo') 155 | expect(node.innerHTML).to.equal '
hello
' 156 | 157 | it 'inputtype.classes#id::css should work 2', -> 158 | view = -> ['text.btn#button1##width:200px;color:red'] 159 | comp = dc({view}) 160 | comp.mount('#demo') 161 | node = document.querySelector('#demo') 162 | expect(node.innerHTML).to.equal '' 163 | 164 | it 'password.classes#id::css should work', -> 165 | view = -> ['password.btn#button1##width:200px;color:red'] 166 | comp = dc({view}) 167 | comp.mount('#demo') 168 | node = document.querySelector('#demo') 169 | expect(node.innerHTML).to.equal '' 170 | 171 | describe 'mount embedded dc components', -> 172 | it 'should mount embedded component and auto watch it', -> 173 | data = {message:"I am embedded"} 174 | view = (data) -> ['div', data.message] 175 | embedded = dc({data, view}) 176 | comp = dc({view:embedded}) 177 | comp.mount('#demo') 178 | expect(comp.node.innerHTML).to.equal 'I am embedded' 179 | data.message = "new embedded message" 180 | comp.update() 181 | expect(comp.node.innerHTML).to.equal "new embedded message" 182 | 183 | it 'embedded component will not auto update if stop watching it', -> 184 | data = {message:"I am embedded"} 185 | view = (data) -> ['div', data.message] 186 | embedded = dc({data, view}) 187 | comp = dc({view:embedded}) 188 | comp.mount('#demo') 189 | embedded.stopWatch() 190 | expect(comp.node.innerHTML).to.equal 'I am embedded' 191 | data.message = "new embedded message" 192 | comp.update() 193 | expect(comp.node.innerHTML).to.equal "I am embedded" 194 | 195 | xit 'should NOT mount the same one component in different places', -> 196 | # this test will result 9 errors in devtools console: 197 | # unique keys warnings 198 | # Uncaught Error: component should be mounted under only one place 199 | # the above should be the expected behaviour. 200 | data = {message:"I am embedded"} 201 | view = (data) -> ['div', data.message] 202 | embedded = dc({data, view}) 203 | comp = dc({view:['div', embedded, embedded]}) 204 | window.onerror = (error) -> 205 | throw error 206 | expect(-> comp.mount('#demo')).to.throw() 207 | 208 | it 'should mount the embedded component copy', -> 209 | data = {message:"I am embedded"} 210 | view = (data) -> ['div', data.message] 211 | embedded = dc({data, view}) 212 | embedded.watch() 213 | embedded2 = embedded.copy() 214 | embedded2.watch() 215 | comp = dc({view:['div', embedded, embedded2]}) 216 | comp.mount('#demo') 217 | expect(comp.node.innerHTML).to.equal '
I am embedded
I am embedded
' 218 | data.message = "new embedded message" 219 | expect(comp.node.innerHTML).to.equal '
new embedded message
new embedded message
' 220 | 221 | it 'should mount the embedded component copy 2', -> 222 | data = {show1:true, message1:"I am embedded 1", message2:"I am embedded 2"} 223 | view = (data) -> 224 | if data.show1 225 | ['div', data.message1] 226 | else 227 | ['div', data.message2] 228 | embedded = dc({data, view}) 229 | embedded.watch() 230 | embedded2 = embedded.copy().watch() 231 | comp = dc({view:['div', embedded, embedded2]}) 232 | comp.mount('#demo') 233 | expect(embedded.node.innerHTML).to.equal 'I am embedded 1' 234 | expect(comp.node.innerHTML).to.equal '
I am embedded 1
I am embedded 1
' 235 | data.show1 = false 236 | expect(comp.node.innerHTML).to.equal '
I am embedded 2
I am embedded 2
' 237 | 238 | it 'should process rebol style function call in view item', -> 239 | if_ = (test, then_, else_) -> 240 | if test 241 | then_ 242 | else 243 | else_ 244 | item = normalizeItem [if_, 0, 1, 2] 245 | 246 | expect(item).to.equal '2' 247 | 248 | iit 'should update embedded sub components', -> 249 | view = -> 250 | @selected 251 | comp = dc {view} 252 | view = -> 253 | ['div', 'comp1'] 254 | comp1 = dc {view} 255 | view = -> 256 | ['div', 'comp2'] 257 | comp2 = dc {view} 258 | comp.selected = comp1 259 | comp.mount('#demo') 260 | comp.selected = comp2 261 | console.log('comps: ', comp, comp1, comp2) 262 | comp.update() -------------------------------------------------------------------------------- /test/test-react-proxy.coffee: -------------------------------------------------------------------------------- 1 | {expect, iit, idescribe, nit, ndescribe} = require 'bdd-test-helper' 2 | 3 | import React, {Component} from 'react' 4 | import ReactDom from 'react-dom' 5 | 6 | dc.addReactProxy React, ReactDom, Component 7 | 8 | {newDemoNode} = require './helper' 9 | 10 | {normalizeDomElement} = require 'dc-util' 11 | 12 | 13 | describe "test react proxy", -> 14 | beforeEach -> 15 | demoNode = normalizeDomElement('#demo2') 16 | 17 | if demoNode.childNodes.length 18 | node = demoNode.childNodes[0] 19 | demoNode.removeChild(node) 20 | 21 | # tell React do not warn about this 22 | demoNode._reactRootContainer = undefined 23 | return 24 | 25 | 26 | describe 'update ReactBlock', -> 27 | 28 | it 'should mount simple react div block 1', -> 29 | comp = dc {view: ['div', 'hello']} 30 | comp.mount('#demo2') 31 | 32 | it 'should mount embedded react div block 2', -> 33 | comp = dc {view: ['div', {}, ['div', {key:1}, 'hello']]} 34 | comp.mount('#demo2') 35 | comp.update() 36 | 37 | it 'should mount react dc + div block', -> 38 | data = {showing:true, message:'dc'} 39 | view = (data) -> 40 | if data.showing 41 | return ['div', data.message] 42 | else 43 | return null 44 | comp = dc {data, view} 45 | data.showing = true 46 | data.message = 'hello dc' 47 | comp.mount('#demo2') 48 | data.showing = false 49 | comp.update() 50 | 51 | 52 | it 'should mount and update react dc + if-else div block 1', -> 53 | data = {showing:true, message1: 'hello dc 1', message2: 'hello dc 2'} 54 | view = (data) -> 55 | if data.showing 56 | ['div', data.message1] 57 | else 58 | ['div', data.message2] 59 | comp = dc {data, view} 60 | data.showing = true 61 | comp.mount('#demo2') 62 | data.showing = false 63 | comp.update() 64 | 65 | it 'should mount and update react dc + if_ div block 2', -> 66 | data = {showing:true, message1: 'hello dc 1', message2:'hello dc 2'} 67 | view = () -> 68 | if this.showing 69 | ['div', data.message1] 70 | else 71 | ['div', data.message2] 72 | comp = dc {data, view} 73 | data.showing = true 74 | comp.mount('#demo2') 75 | data.showing = false 76 | comp.update() 77 | data.showing = true 78 | comp.update() 79 | data.showing = false 80 | comp.update() 81 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | # todo 2 | test material-ui in domcom 11.25 3 | self controled component, e.g. dialog.open(), dialog.close() 11.25 4 | test antd in domcom 11.25 5 | documents 11.25 6 | VueProxy 11.25 7 | 8 | ### done 9 | ####new design 10 | dc-directive 12.8-12.8 11 | watch component and it's data 12.8-12.8 12 | check only one instance of the component in th dom tree. 11.28-12.8 13 | Component.extend, Component.copy 11.28-12.8 14 | go on removing unused code 11.27-11.28 15 | decouple dc and dc-proxy 11.27--11.28 16 | binds function in config field 11.27-11.27 17 | check the fields in config, do not conflict with Component' prototype 11.27-11.27 18 | test event in domcom 11.25-11.25 add one test 19 | test antd in domcom 11.25-11.25 started with simple button 20 | test material-ui in domcom 11.25-11.25 started with simple button 21 | component in view 11.25-11.25 22 | test classname with false value 11.25-11.25 23 | multiple props in on list element 11.25-11.25 24 | class in both head string and props 11.2-11.25 25 | style in both head string and props 11.25-11.25 26 | dc.update: update all mounted component 11.25-11.25 27 | 28 | data:Component.getData() 29 | view:Component.getView 30 | [] (embedded list) style view 31 | ReactProxy.render(), renderItem, dcutil normalizeItem 32 | 33 | ==================================================================================================================== 34 | ####old design 35 | * separate the code for updating dom and attach/detach dom 36 | * flatten the render hierarchy, skip the call to inactive component level 37 | * delegation to events 38 | * error processing: dc.onerror and dc.error 39 | * minify the removing and reinsert of node as possible 40 | * rendering html on the server side: https://github.com/taijiweb/dc-html 41 | * instead of comparing TransformComponent.content too early, only refresh while new baseComponent is different from old baseComponent 42 | * browser compatibility 43 | * use requestAnimationFrame 44 | * Component Event: on, off, emit 45 | * beforeMount, afterMount 46 | * jquery style api 47 | * support object with Each 48 | * rename Repeat to Each 49 | * multiple test if-else if-else, similar to "cond" in lisp 50 | cond: (test, component, ..., otherwise) 51 | * promise 52 | * allow to modify the component 53 | * route 54 | * the property of the component can only be a function or a value 55 | * the value of the private events property of the component always be array of functions, provide bind/unbind method 56 | * skip the inactive component 57 | * only render the difference, according the cache 58 | 59 | --------------------------------------------------------------------------------