├── .babelrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE-pt.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── bin ├── chromedriver ├── chromedriver-mac ├── chromedriver-win ├── phantomjs └── selenium-server-standalone-3.0.1.jar ├── config ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js ├── dist ├── capivara.js ├── capivara.js.map └── capivara.min.js ├── index.js ├── karma.conf.js ├── nightwatch.conf.js ├── nightwatch.json ├── package-lock.json ├── package.json ├── src ├── common.ts ├── constants.ts ├── core │ ├── capivara.instance.ts │ ├── component.config.ts │ ├── component.instance.ts │ ├── component.ts │ ├── controller.ts │ ├── element.ts │ ├── eval.ts │ ├── index.ts │ ├── magic │ │ ├── check.context.ts │ │ ├── context.ts │ │ ├── magic.ts │ │ └── types │ │ │ ├── angular.context.ts │ │ │ ├── angularjs.context.ts │ │ │ ├── capivara.context.ts │ │ │ ├── react.context.ts │ │ │ └── vuejs.context.ts │ ├── observer │ │ ├── index.ts │ │ ├── polyfill.ts │ │ └── util.ts │ └── util │ │ └── keycodes.enum.ts ├── decorators │ ├── component-state.ts │ ├── component.ts │ ├── controller.ts │ └── index.ts ├── index.ts ├── map │ ├── directive │ │ ├── cp-attr.ts │ │ ├── cp-blur.ts │ │ ├── cp-change.ts │ │ ├── cp-class.ts │ │ ├── cp-click.ts │ │ ├── cp-disabled.ts │ │ ├── cp-else-if.ts │ │ ├── cp-else.ts │ │ ├── cp-focus.ts │ │ ├── cp-hide.ts │ │ ├── cp-if.ts │ │ ├── cp-init.ts │ │ ├── cp-key.ts │ │ ├── cp-model.ts │ │ ├── cp-mouse.ts │ │ ├── cp-repeat.ts │ │ ├── cp-show.ts │ │ ├── cp-style.ts │ │ └── directive.interface.ts │ └── map-dom.ts └── scope │ ├── scope.proxy.ts │ └── scope.ts ├── test ├── e2e │ ├── cpBlur │ │ ├── template.html │ │ └── test.js │ ├── cpChange │ │ ├── template.html │ │ └── test.js │ ├── cpClass │ │ ├── template.html │ │ └── test.js │ ├── cpClick │ │ ├── template.html │ │ └── test.js │ ├── cpDisabled │ │ ├── template.html │ │ └── test.js │ ├── cpDoubleClick │ │ ├── template.html │ │ └── test.js │ ├── cpElse │ │ ├── template.html │ │ └── test.js │ ├── cpElseIf │ │ ├── template.html │ │ └── test.js │ ├── cpFocus │ │ ├── template.html │ │ └── test.js │ ├── cpHide │ │ ├── template.html │ │ └── test.js │ ├── cpIf │ │ ├── template.html │ │ └── test.js │ ├── cpInit │ │ ├── template.html │ │ └── test.js │ ├── cpKey │ │ ├── template.html │ │ └── test.js │ ├── cpMax │ │ ├── template.html │ │ └── test.js │ ├── cpMaxLength │ │ ├── template.html │ │ └── test.js │ ├── cpMin │ │ ├── template.html │ │ └── test.js │ ├── cpModel │ │ ├── template.html │ │ └── test.js │ ├── cpMouse │ │ ├── template.html │ │ └── test.js │ ├── cpPlaceholder │ │ ├── template.html │ │ └── test.js │ ├── cpRepeat │ │ ├── template.html │ │ └── test.js │ ├── cpShow │ │ ├── template.html │ │ └── test.js │ ├── cpSrc │ │ ├── template.html │ │ └── test.js │ ├── cpStep │ │ ├── template.html │ │ └── test.js │ ├── cpStyle │ │ ├── template.html │ │ └── test.js │ ├── index.js │ ├── interpolation │ │ ├── template.html │ │ └── test.js │ └── noBind │ │ ├── template.html │ │ └── test.js └── spec │ ├── capivara-change.spec.ts │ ├── capivara-class.spec.ts │ ├── capivara-click.spec.ts │ ├── capivara-common.spec.ts │ ├── capivara-component-instance.spec.ts │ ├── capivara-component.spec.ts │ ├── capivara-disabled.spec.ts │ ├── capivara-doubleclick.spec.ts │ ├── capivara-else-if.spec.ts │ ├── capivara-else.spec.ts │ ├── capivara-eval.spec.ts │ ├── capivara-focus.spec.ts │ ├── capivara-hide.spec.ts │ ├── capivara-if.spec.ts │ ├── capivara-init.spec.ts │ ├── capivara-interpolation.spec.ts │ ├── capivara-key.spec.ts │ ├── capivara-max.spec.ts │ ├── capivara-maxlength.spec.ts │ ├── capivara-methods.spec.ts │ ├── capivara-min.spec.ts │ ├── capivara-model.spec.ts │ ├── capivara-mouse.spec.ts │ ├── capivara-no-bind.spec.ts │ ├── capivara-placeholder.spec.ts │ ├── capivara-polyfill.spec.ts │ ├── capivara-repeat.spec.ts │ ├── capivara-show.spec.ts │ ├── capivara-src.spec.ts │ ├── capivara-step.spec.ts │ ├── capivara-style.spec.ts │ ├── capivara-title.spec.ts │ └── capivara-util.spec.ts ├── tsconfig.json ├── tslint.json └── webpack-nightwatch-plugin ├── .babelrc ├── .npmignore ├── LICENSE ├── README.md ├── index.js ├── lib └── index.js ├── package.json ├── rollup.config.js ├── test ├── index.spec.js ├── nightwatch.conf.js └── ui │ └── ui.nightwatch.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | // "env" 4 | ] 5 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | 2 | # http://editorconfig.org 3 | 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | indent_style = space 9 | indent_size = 2 10 | end_of_line = lf 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | [*.md] 15 | insert_final_newline = false 16 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "browser": true, 4 | "es6": true 5 | }, 6 | "extends": "eslint:recommended", 7 | "rules": { 8 | 'no-console': 'off', 9 | 'no-undef': 'off', 10 | "indent": [ 11 | "error", 12 | "tab" 13 | ], 14 | "linebreak-style": [ 15 | "error", 16 | "unix" 17 | ], 18 | "quotes": [ 19 | "error", 20 | "single" 21 | ], 22 | "semi": [ 23 | "error", 24 | "always" 25 | ] 26 | } 27 | }; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea/ 3 | coverage/ 4 | selenium-debug.log 5 | reports/ 6 | .nyc_output 7 | coverage.lcov 8 | phantomjsdriver.log 9 | div/ 10 | dev/ 11 | examples/ 12 | demo/ 13 | dev.html -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "undef": true, 3 | "unused": true, 4 | "esversion": 6, 5 | "node": true, 6 | "globals": { 7 | "angular": true, 8 | "capivara": true, 9 | "window": true, 10 | "document": true, 11 | "require": true 12 | } 13 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | bin 2 | example 3 | coverage 4 | test 5 | .idea 6 | config 7 | dev 8 | webpack-nightwatch-plugin 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - node 4 | before_script: 5 | - npm install 6 | script: 7 | - npm run coverage 8 | branches: 9 | only: 10 | - master 11 | - /^greenkeeper/.*$/ 12 | notifications: 13 | email: 14 | on_failure: change 15 | on_success: change -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | education, socio-economic status, nationality, personal appearance, race, 10 | religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [Gumgait@gmail.com](mailto:Gumgait@gmail.com). All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribuindo com CapivaraJS 2 | 3 | Nós gostamos muito de contribuições em nosso projeto, isso faz com que o CapivaraJS fique melhor a cada dia, para isso criamos esse documento que gostaríamos que você seguisse: 4 | 5 | * [Questões e Problemas](#question) 6 | * [Issues e Bugs](#issue) 7 | * [Requisição de novas funcionalidades](#feature) 8 | * [Melhorias de documentação](#docs) 9 | * [Orientação para a Submissão de Issue](#submit) 10 | * [Orientação para a Submissão de Pull Request](#submit-pr) 11 | 12 | ## Questões e Problemas? 13 | 14 | Abrir uma issue não é a melhor maneira de resolver problemas e questões sobre a utilização do CapivaraJS, explicaremos melhor no próximo tópico quando se deve abrir issues, pois isso evita misturar problemas e questões com Bugs dificultando o trabalho de determinar qual a velocidade em que as requisições devem ser atendidas. A maneira mais rápida e eficiente de resolver isso é utilizando nossos grupos, devido a velocidade em que a equipe ou a comunidade pode resolver. Esses são os links para acessar os grupos: 15 | 16 | Nossos links para contato: 17 | - O [Google Group][groups] do CapivaraJS 18 | 19 | ## Issue ou Bug? 20 | 21 | Se você encontrou um bug no código fonte, você pode nos ajudar submetendo uma issue em nosso [Repositório do GitHub][github]. Melhor ainda se essa issue vier com um Pull Request para fixar o problema. 22 | A equipe empenha-se muito na resolução e fechamento de todas as issues que são abertas, infelizmente algumas podem demorar mais tempo que outras para serem fechadas, mas estaremos investindo muito esforço para que o CapivaraJS alcance sempre as expectatívas dos usuários. 23 | **Veja o tópico sobre [Orientações de Submissão](#submit).** 24 | 25 | ## Requisição de novas funcionalidades? 26 | 27 | Você pode requerir uma nova funcionalidade para o CapivaraJS submetendo uma isssue ao nosso [Repositório do GitHub][github] 28 | 29 | Se você quiser pode também não apenas abrir a issue, mas também ajudar na criação da funcionalidade, fazendo descrições bem detalhadas da sua issue, para que o time não tenha dúvidas durante o desenvolvimento. 30 | Caso você consiga criar a issue e já resolver, visite a sessão de [Orientações sobre Pull Request](#submit-pr). 31 | 32 | ## Melhorias de documentação? 33 | 34 | Se você tiver uma sugestão para a documentação, você pode abrir uma issue e descrever o problema ou melhorias que você tenha. 35 | Caso você esteja disposto a resolver o problema de documentação, seja ele pequeno como alguns erros ortográficos ou grandes inserções de texto. É muito importante criar [issues][github-new-issue] comentando qual é seu objetivo e a sua melhoria de documentação, evitando assim trabalho duplicado para outras pessoas que também possam ter encontrado o mesmo problema. 36 | 37 | ## Orientação para a Submissão de Issue 38 | Antes de qualquer submissão de issue, não custa nada passar lá na sessão de [issues][github-issues] e ver se já não foi aberta ou solucionada. 39 | Se a sua issue for um bug que ainda não tenha sido reportado a nós, abra a issue imediatamente. Isso ajuda a concentrar o foco do time de desenvolvimento, pois não será necessário procurar problemas e sim apenas concerta-los, fazendo com que bugs sejam resolvidos com mais eficiência. 40 | 41 | A [nova issue][github-new-issue] contem vários campos que gostaríamos que fossem preenchidos para entendermos melhor o problema e categorizar por nível de urgência. 42 | 43 | Mesmo que já falamos anteriormente reforçar nunca é demais, então aqui vão algumas dicas de como melhorar a documentação da issue, para que ela vá direto ao ponto. 44 | 45 | * **Explicações** - Explique qual o motivo disso ser um problema para você 46 | * **A versão do CapivaraJS** - Não se esqueça de dizer qual é a sua versão utilizada, pois muitas vezes uma migração para uma nova versão do sistema já pode resolver. 47 | * **Reprodução do erro** - Nos mostre um exemplo do problema, pode ser utilizando [JSFiddle][jsfiddle] ou [Plunker][plunker] (ou qualquer outro editor online) para entendermos com mais facilidade 48 | * **Issues Parecidas** - Alguma issue reportada anteriormente é relacionada com a sua? Nos avise. 49 | * **Sugestão para Solução** - Se você conseguiu resolver o problema você mesmo, avise também para ajudar outras pessoas. 50 | 51 | ## Orientação para a Submissão de Pull Request 52 | 53 | Esse é um pequeno tutorial de como enviar pull requests para o [CapivaraJS][CapivaraDoc] 54 | 55 | * Primeiro acesse o github do [CapivaraJS][github] e faça um fork do projeto 56 | * Dentro do seu fork você pode fazer as suas modificações, logo em seguida você pode enviar as suas alterações para o seu fork no github utilizando os seguintes comandos, dentro da pasta do seu projeto 57 | 58 | git add . 59 | 60 | git commit -m "Adicione aqui a mensagem que você quer que apareça" 61 | 62 | git push origin (master ou outraBranch) 63 | 64 | * Agora entre novamente em nosso [github][github] e abra o pull request 65 | 66 | * Escolha a opção de comparação entre o nosso repositório e o seu fork clicando em **compare across forks** 67 | * Não se esqueça de nos dar permissão para editarmos qualquer código que você nos envie marcando a opção **Allow edits from maintainers** 68 | * Agora é so enviar o seu **Pull Request** e esperar nossa resposta 69 | 70 | 71 | 72 | [github-issues]: https://github.com/CapivaraJS/capivarajs/issues 73 | [github-new-issue]: https://github.com/CapivaraJS/capivarajs/issues/new 74 | [github]: https://github.com/CapivaraJS/capivarajs 75 | [groups]: https://groups.google.com/d/forum/capivarajs 76 | [individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html 77 | [jsfiddle]: http://jsfiddle.net/ 78 | [plunker]: https://plnkr.co/ 79 | [CapivaraDoc]: https://capivarajs.github.io/ 80 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE-pt.md: -------------------------------------------------------------------------------- 1 | ### Passo 1: Você está no local correto? 2 | 3 | * Para submter isssues ou features relacionadas com o código, adicione uma [issue](github) em nosso Github. 4 | * Para dúvidas ou questões sobre utilização, utilize o [Google Groups](https://groups.google.com/forum/#!forum/capivarajs) que nós responderemos. 5 | 6 | ### Passo 2: Descreva seu ambiente 7 | 8 | * Versão do SO: _____ 9 | * Versão do CapivaraJS: _____ 10 | * Versão do Npm: _____ 11 | 12 | ### Passo 3: Descreva o problema: 13 | 14 | #### Passos para reprodução do erro: 15 | 16 | 1. _____ 17 | 2. _____ 18 | 3. _____ 19 | 20 | #### Resultados da execução: 21 | 22 | * O que aconteceu? Você pode nos dar uma descrição, um print de saída ou até um documento de texto. 23 | 24 | #### Resultado Esperado: 25 | 26 | * Nos diga qual era a saída esperada do seu programa. 27 | #### Seu código: 28 | 29 | ``` 30 | // TODO(você): Coloque seu código para mostrar o problema 31 | ``` 32 | * Se você preferir, pode colocar o código no [JSFiddle][jsfiddle] ou [Plunker][plunker] e nos enviar o link. 33 | 34 | ### Conseguiu desenvolver uma solução? 35 | 36 | Abra um [pull request] e faça a submissão do seu código. 37 | 38 | #### Esse template de issue foi baseado no template desse [Github](https://github.com/googlesamples/google-services). 39 | 40 | [jsfiddle]: http://jsfiddle.net/ 41 | [plunker]: https://plnkr.co/ 42 | [github]: https://github.com/CapivaraJS/capivarajs 43 | [google-github]: https://github.com/googlesamples/google-services 44 | [pull request]: https://github.com/CapivaraJS/capivarajs/compare 45 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Step 1: Are you in the right place? 2 | 3 | * For issues or feature requests related to the code in [this repository](github) file a Github issue. 4 | * For general technical questions, post a question on [Google Groups](https://groups.google.com/forum/#!forum/capivarajs) tagged appropriately. 5 | 6 | ### Step 2: Describe your environment 7 | 8 | * OS version: _____ 9 | * CapivaraJS version: _____ 10 | * Npm Version: _____ 11 | 12 | ### Step 3: Describe the problem: 13 | 14 | #### Steps to reproduce: 15 | 16 | 1. _____ 17 | 2. _____ 18 | 3. _____ 19 | 20 | #### Observed Results: 21 | 22 | * What happened? This could be a description, log output, etc. 23 | 24 | #### Expected Results: 25 | 26 | * What did you expect to happen? 27 | 28 | #### Relevant Code: 29 | 30 | ``` 31 | // TODO(you): code here to reproduce the problem 32 | ``` 33 | * If you prefer, you can put the code on [JSFiddle][jsfiddle] or [Plunker][plunker]. 34 | 35 | ### Did you develop a solution? 36 | Open a [pull request] and submit your code. 37 | 38 | 39 | #### The issue template are based on this [GitHub](https://github.com/googlesamples/google-services). 40 | 41 | [jsfiddle]: http://jsfiddle.net/ 42 | [plunker]: https://plnkr.co/ 43 | [github]: https://github.com/CapivaraJS/capivarajs 44 | [google]: https://github.com/googlesamples/google-services 45 | [pull request]: https://github.com/CapivaraJS/capivarajs/compare 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License 3 | 4 | Copyright (c) 2010-2018 Gumga, S/A. https://capivarajs.github.io/ 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | CapivaraJS 3 |

4 | 5 |

6 | Travis 7 | Codecov 8 | Downloads 9 | Version 10 | License 11 |

12 | 13 |

14 | Greenkeeper badge 15 | Join the chat 16 |

17 | 18 | 19 | Atualmente existem vários frameworks que possibilitam a criação de componentes, entretanto tais componentes acabam ficando isolados em determinada tecnologia, fazendo com que uma possível migração seja mais complexa. 20 | 21 | Criamos um **framework híbrido** e suas diretivas são totalmente personalizáveis, tornando assim os componentes independentes da tecnologia utilizada. 22 | 23 | Componentes CapivaraJS são compatíveis com todos frameworks. Experimente! 24 | 25 | _____________________________________________________________________ 26 | 27 | [Ir para documentação / Go to documentation](https://capivarajs.github.io/) 28 | 29 | [Seja um contribuidor / Be a contributor][contributing] 30 | 31 | [contributing]: https://github.com/CapivaraJS/capivarajs/blob/master/CONTRIBUTING.md 32 | 33 | _____________________________________________________________________ 34 | 35 | Nowadays there are a lot of frameworks to component creation, but these components become isolated in the technology. and this increase the complexity to migrate them. 36 | 37 | We create a **hibrid framework** and yours directives are totaly customizable, making your components independent of the used technology 38 | 39 | CapivaraJS components are compatible with all frameworks. Try it! 40 | -------------------------------------------------------------------------------- /bin/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapivaraJS/capivarajs/4e4f735a092b70634d32ebd6d821dae9439a0569/bin/chromedriver -------------------------------------------------------------------------------- /bin/chromedriver-mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapivaraJS/capivarajs/4e4f735a092b70634d32ebd6d821dae9439a0569/bin/chromedriver-mac -------------------------------------------------------------------------------- /bin/chromedriver-win: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapivaraJS/capivarajs/4e4f735a092b70634d32ebd6d821dae9439a0569/bin/chromedriver-win -------------------------------------------------------------------------------- /bin/phantomjs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapivaraJS/capivarajs/4e4f735a092b70634d32ebd6d821dae9439a0569/bin/phantomjs -------------------------------------------------------------------------------- /bin/selenium-server-standalone-3.0.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CapivaraJS/capivarajs/4e4f735a092b70634d32ebd6d821dae9439a0569/bin/selenium-server-standalone-3.0.1.jar -------------------------------------------------------------------------------- /config/webpack.common.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const isTest = process.argv.indexOf('--t') !== -1; 3 | const WebpackNightWatchPlugin = require('../webpack-nightwatch-plugin'); 4 | 5 | const plugins = []; 6 | 7 | if(isTest){ 8 | plugins.push( 9 | new WebpackNightWatchPlugin({ 10 | url: 'nightwatch.conf.js' 11 | }) 12 | ); 13 | } 14 | 15 | module.exports = { 16 | context: __dirname, 17 | entry: { 18 | bundle: path.join(__dirname, '../src', 'index') 19 | }, 20 | plugins: plugins, 21 | resolve: { 22 | extensions: ['.ts', '.tsx', '.js'] 23 | }, 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.(html)$/, 28 | use: 'html-loader' 29 | }, 30 | { 31 | test: /\.tsx?$/, 32 | use: 'ts-loader', 33 | exclude: /node_modules/ 34 | }, 35 | { 36 | test: /\.js$/, 37 | exclude: /node_modules/, 38 | use: 'babel-loader' 39 | }, 40 | { 41 | test: /\.(jpe?g|png|gif|svg|eot|woff2|woff|ttf)$/i, 42 | use: 'file-loader?name=assets/[name].[ext]' 43 | } 44 | ] 45 | } 46 | }; -------------------------------------------------------------------------------- /config/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const merge = require('webpack-merge'); 3 | const webpackCommon = require('./webpack.common'); 4 | 5 | module.exports = merge(webpackCommon, { 6 | mode: 'development', 7 | devtool: 'source-map', 8 | output: { 9 | path: path.join(__dirname, '../dist/'), 10 | filename: 'capivara.js', 11 | publicPath: '/dist/' 12 | }, 13 | devServer: { 14 | inline: true, 15 | host: '0.0.0.0', 16 | port: 1111 17 | }, 18 | plugins: [], 19 | module: { 20 | rules: [] 21 | } 22 | }); -------------------------------------------------------------------------------- /config/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const merge = require('webpack-merge'); 3 | const webpackCommon = require('./webpack.common'); 4 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); 5 | 6 | module.exports = merge(webpackCommon, { 7 | mode: 'production', 8 | output: { 9 | path: path.join(__dirname, '../dist/'), 10 | filename: 'capivara.min.js', 11 | publicPath: '/dist/' 12 | }, 13 | plugins: [ 14 | new UglifyJSPlugin() 15 | ], 16 | module: { 17 | rules: [] 18 | } 19 | }); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | require('./dist/capivara.js'); 2 | module.exports = window.capivara; 3 | 4 | 5 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | config.set({ 3 | 4 | // base path that will be used to resolve all patterns (eg. files, exclude) 5 | basePath: '', 6 | 7 | 8 | // frameworks to use 9 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 10 | frameworks: ['jasmine', 'karma-typescript', 'es6-shim'], 11 | 12 | // list of files / patterns to load in the browser 13 | files: [ 14 | './node_modules/babel-polyfill/dist/polyfill.js', 15 | 'src/*.ts', 16 | 'src/**/*.ts', 17 | 'test/spec/*spec.ts', 18 | ], 19 | 20 | // Configure code coverage reporter 21 | coverageReporter: { 22 | reporters: [ 23 | // generates ./coverage/lcov.info 24 | {type:'lcovonly', subdir: '.'}, 25 | // generates ./coverage/coverage-final.json 26 | {type:'json', subdir: '.'}, 27 | ] 28 | }, 29 | 30 | // list of files to exclude 31 | exclude: [], 32 | 33 | 34 | // preprocess matching files before serving them to the browser 35 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 36 | preprocessors: { 37 | '**/*.ts': ['karma-typescript'] 38 | }, 39 | 40 | karmaTypescriptConfig: { 41 | compilerOptions: { 42 | target: 'ES5', 43 | lib: ['ES2015', 'DOM'] 44 | } 45 | }, 46 | // test results reporter to use 47 | // possible values: 'dots', 'progress' 48 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 49 | reporters: ['progress', 'karma-typescript', 'coverage'], 50 | 51 | 52 | // web server port 53 | port: 9876, 54 | 55 | 56 | // enable / disable colors in the output (reporters and logs) 57 | colors: true, 58 | 59 | 60 | // level of logging 61 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 62 | logLevel: config.LOG_INFO, 63 | 64 | 65 | // enable / disable watching file and executing tests whenever any file changes 66 | autoWatch: true, 67 | 68 | 69 | // start these browsers 70 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 71 | browsers: ['PhantomJS'], 72 | 73 | 74 | // Continuous Integration mode 75 | // if true, Karma captures browsers, runs the tests and exits 76 | singleRun: true, 77 | 78 | // Concurrency level 79 | // how many browser should be started simultaneous 80 | concurrency: Infinity 81 | }); 82 | }; 83 | -------------------------------------------------------------------------------- /nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = (function(settings) { 2 | settings.test_workers = false; 3 | return settings; 4 | })(require('./nightwatch.json')); -------------------------------------------------------------------------------- /nightwatch.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_folders": [ 3 | "test/e2e/index.js" 4 | ], 5 | "output_folder": "reports", 6 | "custom_commands_path": "", 7 | "custom_assertions_path": "", 8 | "page_objects_path": "", 9 | "globals_path": "", 10 | "selenium": { 11 | "start_process": true, 12 | "server_path": "./bin/selenium-server-standalone-3.0.1.jar", 13 | "log_path": "", 14 | "port": 5555, 15 | "cli_args": { 16 | "webdriver.chrome.driver": "./bin/chromedriver" 17 | } 18 | }, 19 | "test_settings": { 20 | "default": { 21 | "launch_url": "http://localhost", 22 | "selenium_port": 5555, 23 | "selenium_host": "localhost", 24 | "silent": true, 25 | "screenshots": { 26 | "enabled": false, 27 | "path": "./screenshots" 28 | }, 29 | "desiredCapabilities": { 30 | "browserName" : "chrome" 31 | }, 32 | "phantom": { 33 | "browserName" : "phantomjs", 34 | "javascriptEnabled" : true, 35 | "acceptSslCerts" : true, 36 | "phantomjs.binary.path" : "./bin/phantomjs", 37 | "phantomjs.cli.args" : ["--ignore-ssl-errors=true"] 38 | }, 39 | "chrome": { 40 | "browserName": "chrome", 41 | "javascriptEnabled": true, 42 | "acceptSslCerts": true, 43 | "chromeOptions": { 44 | "args": [ 45 | "start-fullscreen" 46 | ] 47 | } 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "capivarajs", 3 | "version": "3.10.2", 4 | "description": "Um framework para criação de componentes.", 5 | "main": "./src/index.ts", 6 | "repository": { 7 | "url": "https://github.com/CapivaraJS/capivarajs", 8 | "type": "git" 9 | }, 10 | "scripts": { 11 | "dev": "webpack-dev-server --config ./config/webpack.dev.js", 12 | "prod": "npm run test-single && webpack --config ./config/webpack.dev.js && webpack --config ./config/webpack.prod.js", 13 | "test": "karma start", 14 | "test-single": "karma start --single-run", 15 | "e2e": "webpack-dev-server --config ./config/webpack.dev.js --t true", 16 | "generate-report": "nyc --report-dir coverage npm run test && nyc report --reporter=text", 17 | "coverage": "npm run generate-report && nyc report --reporter=text-lcov > coverage.lcov && codecov" 18 | }, 19 | "author": "Capivara Team.", 20 | "license": "MIT", 21 | "dependencies": { 22 | "lodash.get": "^4.4.2", 23 | "lodash.isequal": "^4.5.0", 24 | "lodash.set": "^4.3.2", 25 | "melanke-watchjs": "^1.4.3" 26 | }, 27 | "keywords": [ 28 | "frameworkjs", 29 | "web components", 30 | "front end", 31 | "documentation", 32 | "components", 33 | "gumga", 34 | "capivara", 35 | "capivarajs", 36 | "js", 37 | "javascript", 38 | "framework" 39 | ], 40 | "nyc": { 41 | "include": [ 42 | "src/*.ts", 43 | "src/**/*.ts" 44 | ], 45 | "exclude": [ 46 | "typings" 47 | ], 48 | "extension": [ 49 | ".ts", 50 | ".js" 51 | ], 52 | "reporter": [ 53 | "json", 54 | "html" 55 | ], 56 | "all": true 57 | }, 58 | "devDependencies": { 59 | "@babel/core": "^7.0.0-beta.42", 60 | "@babel/preset-env": "^7.0.0-beta.42", 61 | "@types/jasmine": "^2.6.3", 62 | "@types/node": "^10.0.3", 63 | "babel-loader": "^7.1.4", 64 | "babel-polyfill": "^6.26.0", 65 | "babel-preset-stage-0": "^6.24.1", 66 | "codecov": "^3.0.0", 67 | "css-loader": "^1.0.0", 68 | "eslint": "^4.19.1", 69 | "extract-text-webpack-plugin": "^4.0.0-beta.0", 70 | "file-loader": "^1.1.5", 71 | "html-loader": "^0.5.1", 72 | "jasmine": "^3.1.0", 73 | "jasmine-core": "^3.1.0", 74 | "karma": "^3.0.0", 75 | "karma-cli": "^1.0.1", 76 | "karma-es6-shim": "^1.0.0", 77 | "karma-jasmine": "^1.1.1", 78 | "karma-phantomjs-launcher": "^1.0.4", 79 | "karma-typescript": "^3.0.12", 80 | "nightwatch": "^0.9.20", 81 | "node-sass": "^4.7.2", 82 | "nyc": "^12.0.1", 83 | "style-loader": "^0.22.0", 84 | "ts-loader": "^4.1.0", 85 | "typescript": "^2.7.2", 86 | "tslint": "^5.9.1", 87 | "uglifyjs-webpack-plugin": "^1.1.2", 88 | "weakset": "^1.0.0", 89 | "webpack": "^4.8.1", 90 | "webpack-cli": "^2.1.3", 91 | "webpack-dev-server": "^3.1.1", 92 | "webpack-merge": "^4.1.2" 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | export const Constants = { 2 | SCOPE_ATTRIBUTE_NAME : '$scope', 3 | EVENT_ATTRIBUTE_NAME : '$event', 4 | REPEAT_ATTRIBUTE_NAME : 'cp-repeat', 5 | REPEAT_INDEX_NAME : '$index', 6 | REPEAT_ATTRIBUTE_OPERATOR : 'in', 7 | MODEL_ATTRIBUTE_NAME : 'cp-model', 8 | CLICK_ATTRIBUTE_NAME : 'cp-click', 9 | DBLCLICK_ATTRIBUTE_NAME : 'cp-dblclick', 10 | SHOW_ATTRIBUTE_NAME : 'cp-show', 11 | IF_ATTRIBUTE_NAME : 'cp-if', 12 | STEP_ATTRIBUTE_NAME : 'cp-step', 13 | MAX_ATTRIBUTE_NAME : 'cp-max', 14 | MAX_LENGTH_ATTRIBUTE_NAME : 'cp-maxlength', 15 | MIN_ATTRIBUTE_NAME : 'cp-min', 16 | ELSE_ATTRIBUTE_NAME : 'cp-else', 17 | ELSE_IF_ATTRIBUTE_NAME : 'cp-else-if', 18 | INIT_ATTRIBUTE_NAME : 'cp-init', 19 | STYLE_ATTRIBUTE_NAME : 'cp-style', 20 | CLASS_ATTRIBUTE_NAME : 'cp-class', 21 | SRC_ATTRIBUTE_NAME : 'cp-src', 22 | KEY_ATTRIBUTE_NAME : 'cp-key', 23 | ATTR_ATTRIBUTE_NAME : 'cp-attr', 24 | DISABLE_ATTRIBUTE_NAME : 'cp-disabled', 25 | START_INTERPOLATION : '[[', 26 | END_INTERPOLATION : ']]', 27 | IGNORE_BINDINGS : 'cp-non-bindable', 28 | FOCUS_ATTRIBUTE_NAME : 'cp-focus', 29 | HIDE_ATTRIBUTE_NAME : 'cp-hide', 30 | BLUR_ATTRIBUTE_NAME : 'cp-blur', 31 | TITLE_ATTRIBUTE_NAME : 'cp-title', 32 | PLACEHOLDER_ATTRIBUTE_NAME: 'cp-placeholder', 33 | MOUSE_ATTRIBUTE_NAME : 'cp-mouse', 34 | CHANGE_ATTRIBUTE_NAME : 'cp-change', 35 | }; 36 | -------------------------------------------------------------------------------- /src/core/component.config.ts: -------------------------------------------------------------------------------- 1 | export interface ComponentConfig { 2 | template?: string; 3 | controller: any; 4 | controllerAs?: string; 5 | bindings?: string[]; 6 | functions?: any[]; 7 | constants?: string[]; 8 | } 9 | -------------------------------------------------------------------------------- /src/core/component.ts: -------------------------------------------------------------------------------- 1 | import { ComponentInstance } from './component.instance'; 2 | 3 | export class Component { 4 | 5 | public componentName: string; 6 | public config: any; 7 | 8 | constructor(_componentName, config) { 9 | this.componentName = _componentName; 10 | this.config = config; 11 | this.customElementsVue(); 12 | } 13 | 14 | private customElementsVue() { 15 | if (window['Vue']) { 16 | window['Vue'].config.ignoredElements = window['Vue'].config.ignoredElements || []; 17 | if (window['Vue'].config.ignoredElements.filter((value) => value === this.componentName).length === 0) { 18 | window['Vue'].config.ignoredElements.push(this.componentName); 19 | } 20 | } 21 | } 22 | 23 | public createNewInstance(elm) { 24 | return new ComponentInstance(elm, this.config); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/core/controller.ts: -------------------------------------------------------------------------------- 1 | import { Constants } from '../constants'; 2 | import { Scope } from '../scope/scope'; 3 | 4 | export class Controller { 5 | 6 | constructor(element?: HTMLElement, callback?) { 7 | const scope = new Scope(element); 8 | callback(scope.getScopeProxy()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/core/element.ts: -------------------------------------------------------------------------------- 1 | export class CapivaraElement { 2 | 3 | private events = {}; 4 | private onEvent; 5 | 6 | constructor(private element) { 7 | if (typeof element === 'string') { 8 | element = document.querySelector(element); 9 | } 10 | } 11 | 12 | public on(eventName, callback) { 13 | if (this.events[eventName]) { 14 | this.events[eventName].push(callback); 15 | } else { 16 | this.events[eventName] = [callback]; 17 | if (!this.onEvent) { 18 | this.onEvent = (evt) => { 19 | (this.events[evt.type] || []).forEach((cb) => cb(evt)); 20 | }; 21 | } 22 | this.element.addEventListener(eventName, this.onEvent); 23 | } 24 | } 25 | 26 | public destroy() { 27 | Object.keys(this.events).forEach((eventName) => { 28 | this.element.removeEventListener(eventName, this.onEvent); 29 | }); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/core/eval.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../common'; 2 | 3 | export namespace Eval { 4 | 5 | export function replaceAt(input, search, replace, start, end) { 6 | return input.slice(0, start) 7 | + input.slice(start, end).replace(search, replace) 8 | + input.slice(end); 9 | } 10 | 11 | export function getIndexStart(arr, currentIndex) { 12 | if (currentIndex === 0) { return 0; } 13 | const getPreviousSize = (i, size) => { 14 | const index = i - 1; 15 | if (index === -1) { return size; } 16 | size += arr[index].length; 17 | return getPreviousSize(index, size); 18 | }; 19 | return getPreviousSize(currentIndex, 0); 20 | } 21 | 22 | export function isVariable(str = '') { 23 | const firstChar = str.charAt(0); 24 | return /[a-zA-Z]/g.test(firstChar) 25 | || firstChar === '$' 26 | || firstChar === '_'; 27 | } 28 | 29 | export function evaluation(source, context, prefix = '') { 30 | const contexts = Array.isArray(context) ? context : [context]; 31 | const referenceSelf = `this.${prefix ? prefix += '.' : ''}`, regex = /\$*[a-z0-9.$]+\s*/gi, keys = source.match(regex); 32 | if (keys && Array.isArray(keys)) { 33 | keys.forEach((str, i) => { 34 | const key = str.replace(/\s/g, ''), 35 | indexStart = getIndexStart(keys, i); 36 | const indexEnd = indexStart + source.substring(indexStart, source.length).indexOf(key) + key.length; 37 | if (!key.includes(referenceSelf)) { 38 | const isVar = !prefix.trim() ? contexts.filter((c) => c.hasOwnProperty(Common.getFirstKey(key))).length > 0 : isVariable(key); 39 | if (isVar) { 40 | source = replaceAt(source, key, `${referenceSelf}${key}`, indexStart, indexEnd); 41 | } 42 | } 43 | }); 44 | } 45 | try { 46 | return function executeCode(str) { 47 | (contexts || []).forEach((c) => Object.keys(c).forEach((key) => { 48 | if (!this[key]) { 49 | this[key] = c[key]; 50 | } 51 | })); 52 | return eval(str); 53 | }.call({}, source); 54 | } catch (e) { throw e; } 55 | } 56 | 57 | export function exec(source, context) { 58 | try { 59 | const contexts = (Array.isArray(context) ? context : [context]); 60 | const contextMerged = Object.assign({}, ...contexts); 61 | const params = Object.keys(contextMerged), paramsValues = params.map((param) => contextMerged[param]); 62 | const toReturn = new Function(...params, ` 63 | const value = ${ source}; 64 | return value == undefined ? '' : Number.isNaN(value) ? 0 : value; 65 | `)(...paramsValues); 66 | if (toReturn === undefined) { return evaluation(source, context); } 67 | return toReturn; 68 | } catch (e) { return evaluation(source, context); } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/core/index.ts: -------------------------------------------------------------------------------- 1 | export { CapivaraInstance } from './capivara.instance'; 2 | export { Controller } from './controller'; 3 | export { ComponentConfig } from './component.config'; 4 | export { ComponentInstance } from './component.instance'; 5 | export { Component } from './component'; 6 | export { Eval } from './eval'; 7 | export * from './observer'; 8 | -------------------------------------------------------------------------------- /src/core/magic/check.context.ts: -------------------------------------------------------------------------------- 1 | import { Common } from "../../common"; 2 | import { AngularContext } from "./types/angular.context"; 3 | import { AngularJSContext } from "./types/angularjs.context"; 4 | import { CapivaraJSContext} from './types/capivara.context'; 5 | import { ReactContext } from "./types/react.context"; 6 | import { VueJSContext } from "./types/vuejs.context"; 7 | 8 | export namespace CheckContext { 9 | 10 | /** 11 | * @pattern https://pt.wikipedia.org/wiki/Chain_of_Responsibility 12 | * @param element 13 | */ 14 | export function getContext(element) { 15 | if (Common.insideComponent(element)) { 16 | return new CapivaraJSContext().getContext(element); 17 | } 18 | const context = new AngularJSContext(new AngularContext(new VueJSContext(new ReactContext(new CapivaraJSContext())))); 19 | return context.getContext(element); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/core/magic/context.ts: -------------------------------------------------------------------------------- 1 | export abstract class Context { 2 | public successor: Context; 3 | protected name: string; 4 | 5 | constructor(context?: Context) { 6 | if (context) { 7 | this.successor = context; 8 | } 9 | } 10 | 11 | public getContext(element) { 12 | if (window[this.name]) { 13 | return this.process(element); 14 | } else if (this.successor) { 15 | return this.successor.getContext(element); 16 | } 17 | } 18 | 19 | public abstract process(element); 20 | } 21 | -------------------------------------------------------------------------------- /src/core/magic/magic.ts: -------------------------------------------------------------------------------- 1 | import { CheckContext } from './check.context'; 2 | 3 | export namespace Magic { 4 | export function getContext(element) { 5 | return CheckContext.getContext(element); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/core/magic/types/angular.context.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "../context"; 2 | 3 | export class AngularContext extends Context { 4 | 5 | constructor(context?: Context) { 6 | super(context); 7 | this.name = 'ng'; 8 | } 9 | 10 | public process(element) { 11 | const probe = window[this.name].probe(element); 12 | if (probe && probe._debugContext && probe._debugContext.context) { 13 | return probe._debugContext.context; 14 | } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/core/magic/types/angularjs.context.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "../context"; 2 | 3 | export class AngularJSContext extends Context { 4 | 5 | constructor(context?: Context) { 6 | super(context); 7 | this.name = 'angular'; 8 | } 9 | 10 | public process(element) { 11 | return window[this.name].element(element).scope(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/core/magic/types/capivara.context.ts: -------------------------------------------------------------------------------- 1 | import { Common } from "../../../common"; 2 | import { Constants } from "../../../constants"; 3 | import { Context } from "../context"; 4 | 5 | export class CapivaraJSContext extends Context { 6 | 7 | constructor(context?: Context) { 8 | super(context); 9 | this.name = 'capivara'; 10 | } 11 | 12 | public process(element) { 13 | if (Common.isComponent(element) && element.parentNode && element.parentNode[Constants.SCOPE_ATTRIBUTE_NAME]) { 14 | return element.parentNode[Constants.SCOPE_ATTRIBUTE_NAME].scope; 15 | } 16 | if (element && element[Constants.SCOPE_ATTRIBUTE_NAME]) { 17 | return element[Constants.SCOPE_ATTRIBUTE_NAME].scope; 18 | } 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/core/magic/types/react.context.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "../context"; 2 | 3 | export class ReactContext extends Context { 4 | 5 | constructor(context?: Context) { 6 | super(context); 7 | this.name = 'React'; 8 | } 9 | 10 | private constainsAttr(attr, element) { 11 | let keyValue; 12 | for (const key in element) { 13 | if (key.startsWith('__reactInternalInstance$')) { 14 | keyValue = key; 15 | break; 16 | } 17 | } 18 | return keyValue; 19 | } 20 | 21 | public process(element) { 22 | const key = this.constainsAttr('__reactInternalInstance$', element); 23 | if (key) { 24 | const fiberNode = element[key]; 25 | if (fiberNode && fiberNode._debugOwner) { 26 | return fiberNode._debugOwner.stateNode; 27 | } 28 | } else if (element.parentElement) { 29 | return this.process(element.parentElement); 30 | } 31 | } 32 | 33 | public teste(element) { 34 | if (element.parentElement && element.parentElement.startsWith('__reactInternalInstance$')) { 35 | return element.parentElement.startsWith('__reactInternalInstance$'); 36 | } else if (element.parentElement) { 37 | return this.teste(element.parentElement); 38 | } else { 39 | return; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/core/magic/types/vuejs.context.ts: -------------------------------------------------------------------------------- 1 | import { Context } from "../context"; 2 | 3 | export class VueJSContext extends Context { 4 | 5 | constructor(context?: Context) { 6 | super(context); 7 | this.name = 'Vue'; 8 | } 9 | 10 | public process(element) { 11 | if (element.parentElement && element.parentElement.__vue__) { 12 | return element.parentElement.__vue__; 13 | } else if (element.parentElement) { 14 | return this.process(element.parentElement); 15 | } else { 16 | return; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/core/observer/index.ts: -------------------------------------------------------------------------------- 1 | import { Polyfill } from './polyfill'; 2 | import { Util } from './util'; 3 | 4 | export namespace Observe { 5 | 6 | const watchers = new WeakMap(); 7 | 8 | export function observe(obj, handler) { 9 | if (!obj) { 10 | return; 11 | } 12 | if (!watchers.has(obj)) { 13 | watchers.set(obj, [handler]); 14 | this.create(obj, (changes) => { 15 | (watchers.get(obj) || []).forEach((watcher) => { 16 | watcher(changes); 17 | }); 18 | }); 19 | } else { 20 | const handlers = watchers.get(obj); 21 | handlers.push(handler); 22 | watchers.set(obj, handlers); 23 | } 24 | } 25 | 26 | export function unobserve(obj) { 27 | this.destroy(obj); 28 | watchers.delete(obj); 29 | } 30 | 31 | export function create(obj, handler, objCreated = []) { 32 | if (obj && obj.__observer__) { 33 | return false; 34 | } 35 | objCreated.push(obj); 36 | let props = Util.keys(obj); 37 | const propsL = props.length; 38 | Polyfill.setDirtyCheck(obj, 50, updateProperties); 39 | for (let i = 0; i < propsL; i++) { 40 | if (Object.prototype.toString.call(obj[props[i]]) === '[object Object]' || Array.isArray(obj[props[i]])) { 41 | if (objCreated.indexOf(obj[props[i]]) === -1 && !obj[props[i]].__observer__) { 42 | this.create(obj[props[i]], handler, objCreated); 43 | } 44 | } else { 45 | Polyfill.watchProperty(obj, props[i], handler); 46 | } 47 | } 48 | function updateProperties() { 49 | if (!Util.compare(props, Util.keys(obj))) { 50 | Polyfill.updateProperties(Util.diff(props, Util.keys(obj)), obj, handler); 51 | props = Util.keys(obj); 52 | } 53 | } 54 | } 55 | 56 | export function destroy(obj, objDestroyed = []) { 57 | if (!obj || !obj.__observer__) { 58 | return false; 59 | } 60 | 61 | objDestroyed.push(obj); 62 | const props = Object.keys(obj), 63 | propsL = props.length; 64 | 65 | Polyfill.clearDirtyCheck(obj); 66 | 67 | for (let i = 0; i < propsL; i++) { 68 | if (Object.prototype.toString.call(obj[props[i]]) === '[object Object]' || Array.isArray(obj[props[i]])) { 69 | if (objDestroyed.indexOf(obj[props[i]]) === -1 && obj[props[i]].__observer__) { 70 | this.destroy(obj[props[i]], objDestroyed); 71 | } 72 | } else { 73 | Polyfill.unWatchProperty(obj, props[i]); 74 | } 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/core/observer/polyfill.ts: -------------------------------------------------------------------------------- 1 | import { Observe } from './index'; 2 | 3 | export namespace Polyfill { 4 | const keyObserver = '__observer__'; 5 | 6 | export function watchProperty(obj, prop, handler) { 7 | let oldVal = obj[prop]; 8 | let newVal = oldVal; 9 | 10 | const getter = () => { 11 | return newVal; 12 | }; 13 | 14 | const setter = (val) => { 15 | oldVal = newVal; 16 | const value = (newVal = val); 17 | if (oldVal !== val) { 18 | handler([{ 19 | type: 'update', 20 | object: obj, 21 | name: prop, 22 | oldValue: oldVal, 23 | }]); 24 | } 25 | return value; 26 | }; 27 | 28 | if (delete obj[prop]) { 29 | Object.defineProperty(obj, prop, { 30 | get: getter, 31 | set: setter, 32 | enumerable: true, 33 | configurable: true, 34 | }); 35 | } 36 | } 37 | 38 | export function updateProperties(delta, obj, handler) { 39 | const added = delta.added, 40 | deleted = delta.deleted, 41 | hasAdded = !!added.length, 42 | hasDeleted = !!deleted.length, 43 | all = delta.all, 44 | allL = all.length, 45 | response = []; 46 | 47 | for (let i = 0; i < allL; i++) { 48 | watchProperty(obj, all[i], handler); 49 | if (hasAdded && i <= added.length) { 50 | response.push({ 51 | type: 'add', 52 | object: obj, 53 | name: added[i], 54 | }); 55 | } 56 | if (hasDeleted && i <= deleted.length) { 57 | response.push({ 58 | type: 'deleted', 59 | object: obj, 60 | name: deleted[i], 61 | }); 62 | } 63 | } 64 | Observe.destroy(obj); 65 | Observe.create(obj, handler); 66 | handler(response); 67 | } 68 | 69 | export function unWatchProperty(obj, prop) { 70 | const val = obj[prop]; 71 | delete obj[prop]; 72 | obj[prop] = val; 73 | } 74 | 75 | export function setDirtyCheck(obj, time, fn) { 76 | Object.defineProperty(obj, keyObserver, { 77 | enumerable: false, 78 | configurable: true, 79 | writable: false, 80 | value: setInterval(fn, time), 81 | }); 82 | } 83 | 84 | export function clearDirtyCheck(obj) { 85 | clearInterval(obj[keyObserver]); 86 | delete obj[keyObserver]; 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/core/observer/util.ts: -------------------------------------------------------------------------------- 1 | export namespace Util { 2 | export function compare(arr1, arr2) { 3 | if (!(arr1 instanceof Array) || !(arr2 instanceof Array)) { 4 | throw new TypeError('#compare accepts two parameters, both being Arrays.'); 5 | } 6 | if (arr1.length !== arr2.length) { 7 | return false; 8 | } 9 | for (let i = 0, l = arr1.length; i < l; i++) { 10 | if (arr1[i] instanceof Array && arr2[i] instanceof Array) { 11 | if (!this.compare(arr1[i], arr2[i])) { 12 | return false; 13 | } 14 | } else if (arr1[i] !== arr2[i]) { 15 | return false; 16 | } 17 | } 18 | return true; 19 | } 20 | export function diff(arr1, arr2) { 21 | if (!arr1 || !arr2 || !(arr1 instanceof Array) || !(arr2 instanceof Array)) { 22 | throw new TypeError('#diff accepts two parameters, both being Arrays.'); 23 | } 24 | const a = [], 25 | diffValue: any = {}, 26 | a1L = arr1.length, 27 | a2L = arr2.length; 28 | 29 | diffValue.added = []; 30 | diffValue.deleted = []; 31 | diffValue.all = []; 32 | for (let i = 0; i < a1L; i++) { 33 | a[arr1[i]] = 1; 34 | } 35 | for (let j = 0; j < a2L; j++) { 36 | if (a[arr2[j]]) { 37 | try { 38 | delete a[arr2[j]]; 39 | } catch (e) {} 40 | } else { 41 | a[arr2[j]] = 2; 42 | } 43 | } 44 | for (const k in a) { 45 | if (k) { 46 | diffValue.all.push(k); 47 | if (a[k] === 1) { 48 | diffValue.deleted.push(k); 49 | } else { 50 | diffValue.added.push(k); 51 | } 52 | } 53 | } 54 | return diffValue; 55 | } 56 | 57 | export function keys(obj) { 58 | if (Object.prototype.toString.call(obj) !== '[object Object]' && !Array.isArray(obj)) { 59 | return []; 60 | } 61 | const props = []; 62 | for (const prop in obj) { 63 | if (prop) { 64 | props.push(prop); 65 | } 66 | } 67 | return props; 68 | } 69 | 70 | export function clone(obj) { 71 | const a = []; 72 | for (const prop in obj) { 73 | if (prop) { 74 | a[prop] = obj[prop]; 75 | } 76 | } 77 | return a; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/core/util/keycodes.enum.ts: -------------------------------------------------------------------------------- 1 | export enum KeyCode { 2 | BACKSPACE = 8, 3 | TAB = 9, 4 | ENTER = 13, 5 | SHIFT = 16, 6 | CTRL = 17, 7 | ALT = 18, 8 | PAUSEBREAK = 19, 9 | CAPSLOCK = 20, 10 | ESCAPE = 27, 11 | SPACE = 32, 12 | PAGEUP = 33, 13 | PAGEDOWN = 34, 14 | END = 35, 15 | HOME = 36, 16 | LEFTARROW = 37, 17 | UPARROW = 38, 18 | RIGHTARROW = 39, 19 | DOWNARROW = 40, 20 | INSERT = 45, 21 | DELETE = 46, 22 | ZERO = 48, 23 | CLOSEDPAREN = ZERO, 24 | ONE = 49, 25 | EXCLAMATIONMARK = ONE, 26 | TWO = 50, 27 | ATSIGN = TWO, 28 | THREE = 51, 29 | POUNDSIGN = THREE, 30 | HASH = POUNDSIGN, 31 | FOUR = 52, 32 | DOLLARSIGN = FOUR, 33 | FIVE = 53, 34 | PERCENTSIGN = FIVE, 35 | SIX = 54, 36 | CARET = SIX, 37 | HAT = CARET, 38 | SEVEN = 55, 39 | AMPERSAND = SEVEN, 40 | EIGHT = 56, 41 | STAR = EIGHT, 42 | ASTERIK = STAR, 43 | NINE = 57, 44 | OPENPAREN = NINE, 45 | A = 65, 46 | B = 66, 47 | C = 67, 48 | D = 68, 49 | E = 69, 50 | F = 70, 51 | G = 71, 52 | H = 72, 53 | I = 73, 54 | J = 74, 55 | K = 75, 56 | L = 76, 57 | M = 77, 58 | N = 78, 59 | O = 79, 60 | P = 80, 61 | Q = 81, 62 | R = 82, 63 | S = 83, 64 | T = 84, 65 | U = 85, 66 | V = 86, 67 | W = 87, 68 | X = 88, 69 | Y = 89, 70 | Z = 90, 71 | LEFTWINDOWKEY = 91, 72 | RIGHTWINDOWKEY = 92, 73 | SELECTKEY = 93, 74 | NUMPAD0 = 96, 75 | NUMPAD1 = 97, 76 | NUMPAD2 = 98, 77 | NUMPAD3 = 99, 78 | NUMPAD4 = 100, 79 | NUMPAD5 = 101, 80 | NUMPAD6 = 102, 81 | NUMPAD7 = 103, 82 | NUMPAD8 = 104, 83 | NUMPAD9 = 105, 84 | MULTIPLY = 106, 85 | ADD = 107, 86 | SUBTRACT = 109, 87 | DECIMALPOINT = 110, 88 | DIVIDE = 111, 89 | F1 = 112, 90 | F2 = 113, 91 | F3 = 114, 92 | F4 = 115, 93 | F5 = 116, 94 | F6 = 117, 95 | F7 = 118, 96 | F8 = 119, 97 | F9 = 120, 98 | F10 = 121, 99 | F11 = 122, 100 | F12 = 123, 101 | NUMLOCK = 144, 102 | SCROLLLOCK = 145, 103 | SEMICOLON = 186, 104 | EQUALS = 187, 105 | COMMA = 188, 106 | DASH = 189, 107 | PERIOD = 190, 108 | UNDERSCORE = DASH, 109 | PLUSSIGN = EQUALS, 110 | FORWARDSLASH = 191, 111 | TILDE = 192, 112 | GRAVEACCENT = TILDE, 113 | OPENBRACKET = 219, 114 | CLOSEDBRACKET = 221, 115 | QUOTE = 222, 116 | } 117 | -------------------------------------------------------------------------------- /src/decorators/component-state.ts: -------------------------------------------------------------------------------- 1 | export interface OnInit { 2 | $onInit(): void; 3 | } 4 | 5 | export interface OnViewInit { 6 | $onViewInit(): void; 7 | } 8 | 9 | export interface OnChanges { 10 | $onChanges(): void; 11 | } 12 | 13 | export interface OnDestroy { 14 | $onDestroy(): void; 15 | } 16 | 17 | export interface Bindings { 18 | $bindings: any; 19 | } 20 | 21 | export interface Functions { 22 | $functions: any; 23 | } 24 | 25 | export interface Constants { 26 | $constants: any; 27 | } 28 | -------------------------------------------------------------------------------- /src/decorators/component.ts: -------------------------------------------------------------------------------- 1 | import { Capivara } from '../'; 2 | 3 | export interface ComponentInterface { 4 | /** 5 | * @description Name that will be used to invoke the component in html. 6 | */ 7 | tag?: string; 8 | /** 9 | * @description Component HTML template. 10 | */ 11 | template: string; 12 | /** 13 | * @description Update controller name. default: $ctrl 14 | */ 15 | controllerAs?: string; 16 | /** 17 | * @description Css path you want to import. 18 | */ 19 | style?: string; 20 | /** 21 | * @description Declares the constants that will be accepted by component. See https://capivarajs.github.io/#/GettingStarted/Components?id=constants 22 | */ 23 | constants?: string[]; 24 | /** 25 | * @description Declares the functions that will be accepted by component. See https://capivarajs.github.io/#/GettingStarted/Components?id=fun%C3%A7%C3%B5es 26 | */ 27 | functions?: string[]; 28 | /** 29 | * @description Declares the variables that will be accepted by component. See https://capivarajs.github.io/#/GettingStarted/Components?id=bindings 30 | */ 31 | bindings?: string[]; 32 | } 33 | 34 | export const Component = (componentConfig: ComponentInterface) => { 35 | return (target: any) => { 36 | const config = { 37 | template: componentConfig.template, 38 | style: componentConfig.style, 39 | constants: componentConfig.constants, 40 | functions: componentConfig.functions, 41 | bindings: componentConfig.bindings, 42 | controllerAs: componentConfig.controllerAs, 43 | controller: target, 44 | }; 45 | Capivara.component(componentConfig.tag, config); 46 | }; 47 | }; 48 | -------------------------------------------------------------------------------- /src/decorators/controller.ts: -------------------------------------------------------------------------------- 1 | import { Bindings, Constants, Functions } from './component-state'; 2 | 3 | export class Controller implements Bindings, Constants, Functions { 4 | public $bindings; 5 | public $constants; 6 | public $functions; 7 | constructor(public $scope?, public $element?) { } 8 | } 9 | -------------------------------------------------------------------------------- /src/decorators/index.ts: -------------------------------------------------------------------------------- 1 | export { Component } from './component'; 2 | export { Controller } from './controller'; 3 | export * from './component-state'; 4 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Eval } from './core'; 2 | import { CapivaraInstance } from './core/capivara.instance'; 3 | import { Component, Controller } from './decorators'; 4 | 5 | const Capivara: CapivaraInstance = (function initCapivara(ctx, aliasName) { 6 | if (!ctx[aliasName]) { 7 | ctx[aliasName] = new CapivaraInstance(); 8 | ctx[aliasName].core = { 9 | Eval, 10 | Component, 11 | Controller, 12 | Capivara, 13 | }; 14 | } else { 15 | console.warn("Gee! CapivaraJS tried to load more than once."); 16 | } 17 | return ctx[aliasName]; 18 | })(window, 'capivara'); 19 | 20 | export { Capivara }; 21 | export * from './decorators'; 22 | export default Capivara; 23 | -------------------------------------------------------------------------------- /src/map/directive/cp-attr.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPAttr implements Directive { 7 | private readonly element: any; 8 | private map: MapDom; 9 | private attributes = []; 10 | 11 | constructor(_element: HTMLElement, _map: MapDom) { 12 | this.element = _element; 13 | this.map = _map; 14 | Array.from(this.element.attributes).forEach((attribute: any) => { 15 | if (attribute.nodeName && attribute.nodeName.startsWith(Constants.ATTR_ATTRIBUTE_NAME)) { 16 | if (!attribute.value) { 17 | throw new Error(`syntax error ${Constants.ATTR_ATTRIBUTE_NAME} expected arguments`); 18 | } 19 | this.attributes.push(attribute.name); 20 | } 21 | }); 22 | } 23 | 24 | public create() { 25 | this.init(); 26 | } 27 | 28 | public init() { 29 | this.attributes.forEach((attribute) => { 30 | const attributeValue = this.element.getAttribute(attribute); 31 | const attr = attribute.replace(Constants.ATTR_ATTRIBUTE_NAME + '.', ''); 32 | const value = Common.evalInMultiContext(this.element, attributeValue); 33 | if (value === undefined || value === null) { 34 | this.element.setAttribute(attr, ''); 35 | } else { 36 | this.element.setAttribute(attr, value); 37 | } 38 | }); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/map/directive/cp-blur.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPBlur implements Directive { 7 | private attribute; 8 | private element: any; 9 | private map: MapDom; 10 | 11 | constructor(_element: HTMLElement, _map: MapDom) { 12 | this.element = _element; 13 | this.map = _map; 14 | this.element['cpBlur'] = this; 15 | this.attribute = Common.getAttributeCpBlur(this.element); 16 | if (this.attribute === undefined) { 17 | throw new Error(`syntax error ${Constants.BLUR_ATTRIBUTE_NAME} expected arguments`); 18 | } 19 | } 20 | 21 | public create() { 22 | this.init(); 23 | } 24 | 25 | public onBlur(evt) { 26 | Common.executeFunctionCallback(evt.target['cpBlur'].element, evt.target['cpBlur'].attribute, { [Constants.EVENT_ATTRIBUTE_NAME] : evt }); 27 | } 28 | 29 | public init() { 30 | // Remove old event 31 | this.element.removeEventListener('blur', this.onBlur); 32 | // Add new event 33 | this.element.addEventListener('blur', this.onBlur); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/map/directive/cp-change.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPChange implements Directive { 7 | 8 | private attribute; 9 | private element: any; 10 | private map: MapDom; 11 | 12 | constructor(_element: HTMLElement, _map: MapDom) { 13 | this.element = _element; 14 | this.map = _map; 15 | this.attribute = this.element.getAttribute(Constants.CHANGE_ATTRIBUTE_NAME); 16 | if (!this.attribute) { 17 | throw new Error(`syntax error ${Constants.CHANGE_ATTRIBUTE_NAME} expected arguments`); 18 | } 19 | if (!this.element.hasAttribute(Constants.MODEL_ATTRIBUTE_NAME)) { 20 | throw new Error(`syntax error ${Constants.MODEL_ATTRIBUTE_NAME} expected arguments`); 21 | } 22 | } 23 | 24 | public create() { 25 | this.init(); 26 | } 27 | 28 | public onModelChange(newValue, oldValue) { 29 | Common.executeFunctionCallback(this.element, this.attribute, { $newValue: newValue, $oldValue: oldValue }); 30 | } 31 | 32 | public init() { 33 | const modelAttribute = this.element.getAttribute(Constants.MODEL_ATTRIBUTE_NAME).replace(Common.getScope(this.element).scope['__$controllerAs__'] + '.', ''); 34 | Common.getScope(this.element).$unwatch(modelAttribute, this.onModelChange); 35 | Common.getScope(this.element).$watch(modelAttribute, this.onModelChange, this); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/map/directive/cp-class.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { MapDom } from '../map-dom'; 3 | import { Directive } from './directive.interface'; 4 | 5 | export class CPClass implements Directive { 6 | 7 | private readonly element: any; 8 | private readonly attribute; 9 | private map: MapDom; 10 | private elementComment; 11 | private elmScope; 12 | 13 | constructor(_element: HTMLElement, _map: MapDom) { 14 | this.element = _element; 15 | this.element['cpClass'] = this; 16 | this.map = _map; 17 | this.attribute = Common.getAttributeCpClass(this.element); 18 | this.elementComment = document.createComment('cpClass ' + this.attribute); 19 | this.elmScope = Common.getScope(_element); 20 | } 21 | 22 | public create() { 23 | this.init(); 24 | } 25 | 26 | public setClassByObject(classObj) { 27 | if (classObj && window['capivara'].isObject(classObj)) { 28 | Object.keys(classObj).forEach((key) => { 29 | if (classObj[key]) { 30 | this.addClass(key.replace(/ /g, '')); 31 | } else { 32 | this.removeClass(key.replace(/ /g, '')); 33 | } 34 | }); 35 | } 36 | } 37 | 38 | public init() { 39 | try { 40 | this.attribute.split(',') 41 | .map((attr) => { 42 | return { 43 | key: attr.substring(0, attr.indexOf(':')).replace(/'/g, "").replace(/"/, '').replace(/{/g, '').replace(/}/, ''), 44 | value: Common.evalInMultiContext(this.element, attr.substring(attr.indexOf(':') + 1, attr.length).replace(/{/g, '').replace(/}/, '')), 45 | }; 46 | }) 47 | .forEach((cpClass) => { 48 | if (window['capivara'].isObject(cpClass.value)) { 49 | this.setClassByObject(cpClass.value); 50 | } else { 51 | if (cpClass.value) { 52 | this.addClass(cpClass.key.replace(/ /g, '')); 53 | } else { 54 | this.removeClass(cpClass.key.replace(/ /g, '')); 55 | } 56 | } 57 | }); 58 | } catch (e) { 59 | } 60 | } 61 | 62 | public removeClass(className) { 63 | if (this.element.classList && this.element.classList.contains(className)) { 64 | this.element.classList.remove(className); 65 | } else if (!this.element.classList && this.element.className.indexOf(className) !== -1) { 66 | this.element.className = this.element.className.replace(className, ''); 67 | } 68 | } 69 | 70 | public addClass(className) { 71 | if (this.element.classList && !this.element.classList.contains(className)) { 72 | this.element.classList.add(className); 73 | } else if (!this.element.classList && this.element.className.indexOf(className) === -1) { 74 | this.element.className += " " + className; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/map/directive/cp-click.ts: -------------------------------------------------------------------------------- 1 | import {Common} from '../../common'; 2 | import {Constants} from '../../constants'; 3 | import {MapDom} from '../map-dom'; 4 | import {Directive} from './directive.interface'; 5 | 6 | export class CPClick implements Directive { 7 | 8 | private readonly element: any; 9 | private readonly eventName; 10 | private map: MapDom; 11 | private attribute; 12 | 13 | constructor(_element: HTMLElement, _map: MapDom) { 14 | this.element = _element; 15 | this.map = _map; 16 | this.attribute = this.element.getAttribute(Constants.CLICK_ATTRIBUTE_NAME); 17 | this.eventName = 'click'; 18 | if (!this.attribute) { 19 | this.attribute = this.element.getAttribute(Constants.DBLCLICK_ATTRIBUTE_NAME); 20 | this.eventName = 'dblclick'; 21 | } 22 | if (!this.attribute) { 23 | throw new Error(`syntax error cp-${this.eventName} expected arguments`); 24 | } 25 | } 26 | 27 | public create() { 28 | this.init(); 29 | } 30 | 31 | public getIndexRow(element) { 32 | const index = Common.get(Common.getScope(element).scope, Constants.REPEAT_INDEX_NAME); 33 | if (index === undefined && element.parentNode) { 34 | return this.getIndexRow(element.parentNode); 35 | } 36 | return index; 37 | } 38 | 39 | public init() { 40 | const onClick = (evt) => { 41 | this.attribute = this.attribute.trim(); 42 | Common.executeFunctionCallback(this.element, this.attribute, { [Constants.EVENT_ATTRIBUTE_NAME] : evt }); 43 | }; 44 | // Remove old event 45 | this.element.removeEventListener(this.eventName, onClick); 46 | // Add new event 47 | this.element.addEventListener(this.eventName, onClick); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/map/directive/cp-disabled.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPDisabled implements Directive { 7 | 8 | private readonly element: any; 9 | private readonly attribute; 10 | 11 | constructor(_element: HTMLElement, _map: MapDom) { 12 | this.element = _element; 13 | this.attribute = Common.getAttributeCpDisable(this.element); 14 | if (!this.attribute) { 15 | throw new Error(`syntax error ${Constants.DISABLE_ATTRIBUTE_NAME} expected arguments`); 16 | } 17 | } 18 | 19 | public create() { 20 | this.init(); 21 | } 22 | 23 | public init() { 24 | try { 25 | JSON.parse(Common.isValidCondition(this.element, Common.getAttributeCpDisable(this.element))) ? this.elementDisabled() : this.elementEnabled(); 26 | } catch (ex) { 27 | this.elementEnabled(); 28 | } 29 | } 30 | 31 | public elementDisabled() { 32 | this.element.setAttribute('disabled', true); 33 | } 34 | 35 | public elementEnabled() { 36 | this.element.removeAttribute('disabled'); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/map/directive/cp-else-if.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPElseIf implements Directive { 7 | 8 | private readonly element: any; 9 | private readonly attribute; 10 | private readonly elementComment; 11 | private map: MapDom; 12 | private prevElement; 13 | private parentCondition; 14 | private cpElseIf; 15 | 16 | constructor(_element: HTMLElement, _map: MapDom) { 17 | this.element = _element; 18 | this.element['cpElseIf'] = this; 19 | this.attribute = Common.getAttributeCpElseIf(this.element); 20 | if (!this.attribute) { 21 | throw new Error(`syntax error ${Constants.ELSE_IF_ATTRIBUTE_NAME} expected arguments`); 22 | } 23 | this.prevElement = _element.previousSibling; 24 | this.map = _map; 25 | this.elementComment = document.createComment('CPElseIf ' + this.attribute); 26 | } 27 | 28 | public create() { 29 | if (this.element.hasAttribute(Constants.REPEAT_ATTRIBUTE_NAME)) { 30 | return; 31 | } 32 | this.integrationCpElse(); 33 | this.parentCondition = Common.getScope(this.element).parentCondition; 34 | if (!this.parentCondition) { 35 | throw new Error(`syntax error ${Constants.ELSE_IF_ATTRIBUTE_NAME} used on element ` + 36 | `<${this.element.nodeName.toLowerCase()}> without corresponding ${Constants.IF_ATTRIBUTE_NAME}.`); 37 | } 38 | this.init(); 39 | } 40 | 41 | public integrationCpElse() { 42 | const nextElement = this.element.nextElementSibling; 43 | if (nextElement && (nextElement.hasAttribute(Constants.ELSE_ATTRIBUTE_NAME) || nextElement.hasAttribute(Constants.ELSE_IF_ATTRIBUTE_NAME))) { 44 | Common.getScope(nextElement).parentCondition = this; 45 | } 46 | } 47 | 48 | public init() { 49 | if (!this.element || this.element.hasAttribute(Constants.REPEAT_ATTRIBUTE_NAME)) { 50 | return; 51 | } 52 | try { 53 | if (!Common.isValidCondition(this.parentCondition.element, Common.getAttributeCpIf(this.parentCondition.element))) { 54 | Common.createElement(this.element, this.elementComment); 55 | if (!Common.isValidCondition(this.element, this.attribute)) { 56 | Common.destroyElement(this.element, this.elementComment); 57 | } 58 | } else { 59 | Common.destroyElement(this.element, this.elementComment); 60 | } 61 | } catch (ex) { 62 | Common.destroyElement(this.element, this.elementComment); 63 | } 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/map/directive/cp-else.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPElse implements Directive { 7 | 8 | private readonly element: any; 9 | private readonly elementComment; 10 | private map: MapDom; 11 | private prevElement; 12 | private parentCondition; 13 | 14 | constructor(_element: HTMLElement, _map: MapDom) { 15 | this.element = _element; 16 | if (Common.getAttributeCpElse(this.element)) { 17 | throw new Error(`${Constants.ELSE_ATTRIBUTE_NAME} don't expect arguments`); 18 | } 19 | this.prevElement = _element.previousSibling; 20 | this.map = _map; 21 | this.elementComment = document.createComment('cpElse'); 22 | } 23 | 24 | public create() { 25 | if (this.element.hasAttribute(Constants.REPEAT_ATTRIBUTE_NAME)) { 26 | return; 27 | } 28 | this.parentCondition = Common.getScope(this.element).parentCondition; 29 | if (!this.parentCondition) { 30 | throw new Error(`syntax error ${Constants.ELSE_ATTRIBUTE_NAME} used on element ` + 31 | `<${this.element.nodeName.toLowerCase()}> without corresponding ${Constants.IF_ATTRIBUTE_NAME}.`); 32 | 33 | } 34 | this.init(); 35 | } 36 | 37 | public hasValidCondition(_element, conditions) { 38 | if (_element && ((_element.hasAttribute && _element.hasAttribute(Constants.IF_ATTRIBUTE_NAME)) || (_element.nodeType === 8 && _element.data.indexOf('cpIf') !== -1))) { 39 | if (_element['$$cpDestroyed']) { return false; } 40 | return !((_element.nodeType === 8 && _element.data.indexOf('cpIf') !== -1) && conditions.length === 0); 41 | } 42 | if (_element && _element.previousSibling) { 43 | if (_element.hasAttribute && _element.hasAttribute(Constants.ELSE_IF_ATTRIBUTE_NAME)) { 44 | conditions.push(_element); 45 | } 46 | return this.hasValidCondition(_element.previousSibling, conditions); 47 | } 48 | } 49 | 50 | public init() { 51 | if (!this.element || this.element.hasAttribute(Constants.REPEAT_ATTRIBUTE_NAME)) { 52 | return; 53 | } 54 | try { 55 | Common.createElement(this.element, this.elementComment); 56 | if (this.hasValidCondition(this.element, [])) { 57 | Common.destroyElement(this.element, this.elementComment); 58 | } 59 | } catch (ex) { 60 | Common.destroyElement(this.element, this.elementComment); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/map/directive/cp-focus.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPFocus implements Directive { 7 | private attribute; 8 | private element: any; 9 | private map: MapDom; 10 | 11 | constructor(_element: HTMLElement, _map: MapDom) { 12 | this.element = _element; 13 | this.map = _map; 14 | this.element['cpFocus'] = this; 15 | this.attribute = Common.getAttributeCpFocus(this.element); 16 | if (this.attribute === undefined) { 17 | throw new Error(`syntax error ${Constants.FOCUS_ATTRIBUTE_NAME} expected arguments`); 18 | } 19 | } 20 | 21 | public create() { 22 | this.init(); 23 | } 24 | 25 | public onFocus(evt) { 26 | Common.executeFunctionCallback(evt.target['cpFocus'].element, evt.target['cpFocus'].attribute, { [Constants.EVENT_ATTRIBUTE_NAME] : evt }); 27 | } 28 | 29 | public init() { 30 | // Remove old event 31 | this.element.removeEventListener('focus', this.onFocus); 32 | // Add new event 33 | this.element.addEventListener('focus', this.onFocus); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/map/directive/cp-hide.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPHide implements Directive { 7 | 8 | private element: any; 9 | private map: MapDom; 10 | private attribute; 11 | private initialDisplay; 12 | 13 | constructor(_element: HTMLElement, _map: MapDom) { 14 | this.element = _element; 15 | this.initialDisplay = this.element.style.display || ''; 16 | this.map = _map; 17 | this.attribute = Common.getAttributeCpHide(this.element); 18 | if (!this.attribute) { 19 | throw new Error(`syntax error ${Constants.HIDE_ATTRIBUTE_NAME} expected arguments`); 20 | } 21 | } 22 | 23 | public create() { 24 | this.init(); 25 | } 26 | 27 | public init() { 28 | try { 29 | Common.isValidCondition(this.element, Common.getAttributeCpHide(this.element)) ? this.hide() : this.show(); 30 | } catch (ex) { 31 | this.hide(); 32 | } 33 | } 34 | 35 | public hide() { 36 | this.element.style.display = 'none'; 37 | } 38 | 39 | public show() { 40 | this.element.style.display = this.initialDisplay; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/map/directive/cp-if.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPIf implements Directive { 7 | 8 | private readonly element: any; 9 | private readonly attribute; 10 | private readonly elementComment; 11 | private map: MapDom; 12 | 13 | constructor(_element: HTMLElement, _map: MapDom) { 14 | this.element = _element; 15 | this.element['cpIf'] = this; 16 | this.map = _map; 17 | this.attribute = Common.getAttributeCpIf(this.element); 18 | if (!this.attribute) { 19 | throw new Error(`syntax error ${Constants.IF_ATTRIBUTE_NAME} expected arguments`); 20 | } 21 | this.elementComment = document.createComment('cpIf ' + this.attribute); 22 | } 23 | 24 | public create() { 25 | if (this.element.hasAttribute(Constants.REPEAT_ATTRIBUTE_NAME)) { 26 | return; 27 | } 28 | this.integrationCpElse(); 29 | this.init(); 30 | } 31 | 32 | public integrationCpElse() { 33 | const nextElement = this.element.nextElementSibling; 34 | if (nextElement && (nextElement.hasAttribute(Constants.ELSE_ATTRIBUTE_NAME) || nextElement.hasAttribute(Constants.ELSE_IF_ATTRIBUTE_NAME))) { 35 | Common.getScope(nextElement).parentCondition = this; 36 | } 37 | } 38 | 39 | public init() { 40 | if (!this.element || this.element.hasAttribute(Constants.REPEAT_ATTRIBUTE_NAME)) { 41 | return; 42 | } 43 | try { 44 | if (!Common.isValidCondition(this.element, Common.getAttributeCpIf(this.element))) { 45 | Common.destroyElement(this.element, this.elementComment); 46 | } else { 47 | Common.createElement(this.element, this.elementComment); 48 | } 49 | } catch (ex) { 50 | Common.destroyElement(this.element, this.elementComment); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/map/directive/cp-init.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPInit implements Directive { 7 | 8 | private readonly element: any; 9 | private attribute; 10 | private map: MapDom; 11 | 12 | constructor(_element: HTMLElement, _map: MapDom) { 13 | this.element = _element; 14 | this.map = _map; 15 | this.attribute = Common.getAttributeCpInit(this.element); 16 | if (!this.attribute) { 17 | throw new Error(`syntax error ${Constants.INIT_ATTRIBUTE_NAME} expected arguments`); 18 | } 19 | } 20 | 21 | public create() { 22 | this.init(); 23 | } 24 | 25 | public init() { 26 | this.attribute = this.attribute.trim(); 27 | Common.evalInMultiContext(this.element, this.attribute); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/map/directive/cp-key.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { KeyCode } from '../../core/util/keycodes.enum'; 4 | import { MapDom } from '../map-dom'; 5 | import { Directive } from './directive.interface'; 6 | 7 | export class CPKey implements Directive { 8 | 9 | private readonly element: any; 10 | private map: MapDom; 11 | private attributes; 12 | 13 | constructor(_element: HTMLElement, _map: MapDom) { 14 | this.element = _element; 15 | this.attributes = []; 16 | this.map = _map; 17 | Array.from(this.element.attributes).forEach((attribute: any) => { 18 | if (attribute.nodeName && attribute.nodeName.startsWith(Constants.KEY_ATTRIBUTE_NAME)) { 19 | if (!attribute.value) { 20 | throw new Error(`syntax error ${Constants.KEY_ATTRIBUTE_NAME} expected arguments`); 21 | } 22 | this.element[attribute.name] = this; 23 | this.attributes.push(attribute.name); 24 | } 25 | }); 26 | } 27 | 28 | public create() { 29 | this.init(); 30 | } 31 | 32 | public onKeyPress(evt) { 33 | const directiveName: any = 'cp-' + evt.type; 34 | if (evt.target && evt.target.hasAttributeStartingWith(directiveName)) { 35 | const attribute = evt.target.getAttributeStartingWith(directiveName)[0].name; 36 | const indexSeparator = attribute.lastIndexOf('.'); 37 | if (indexSeparator === -1) { 38 | Common.executeFunctionCallback(evt.target[attribute].element, evt.target[attribute].element.getAttribute(attribute), { [Constants.EVENT_ATTRIBUTE_NAME] : evt }); 39 | } else { 40 | const watchKeyName = attribute.substring(attribute.lastIndexOf('.') + 1); 41 | const watchKey = !isNaN(watchKeyName) ? Number(watchKeyName) : KeyCode[(watchKeyName || '').toUpperCase()]; 42 | if (watchKey !== undefined && evt.keyCode === watchKey) { 43 | Common.executeFunctionCallback(evt.target[attribute].element, evt.target[attribute].element.getAttribute(attribute), { [Constants.EVENT_ATTRIBUTE_NAME] : evt }); 44 | } 45 | } 46 | } 47 | } 48 | 49 | public init() { 50 | this.attributes.forEach((attribute) => { 51 | const indexSeparator = attribute.lastIndexOf('.'); 52 | const keyType = attribute.substring(0, (indexSeparator === -1 ? attribute.length : indexSeparator)).replace(Constants.KEY_ATTRIBUTE_NAME, ''); 53 | // Remove old event 54 | this.element.removeEventListener(`key${keyType}`, this.onKeyPress); 55 | // Add new event 56 | this.element.addEventListener(`key${keyType}`, this.onKeyPress); 57 | }); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/map/directive/cp-model.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPModel implements Directive { 7 | 8 | private readonly attribute; 9 | private element: any; 10 | private map: MapDom; 11 | 12 | constructor(_element: HTMLElement, _map: MapDom) { 13 | this.element = _element; 14 | this.element['cpModel'] = this; 15 | this.map = _map; 16 | this.attribute = this.element.getAttribute(Constants.MODEL_ATTRIBUTE_NAME); 17 | if (!this.attribute) { 18 | throw new Error(`syntax error ${Constants.MODEL_ATTRIBUTE_NAME} expected arguments`); 19 | } 20 | } 21 | 22 | public create(_element?) { 23 | this.init(); 24 | this.applyModelInValue(); 25 | } 26 | 27 | public init() { 28 | this.map.addCpModels(this); 29 | if (!Common.isComponent(this.element)) { 30 | this.element.removeEventListener('input', this.applyValueInModel); 31 | this.element.addEventListener('input', this.applyValueInModel); 32 | } 33 | } 34 | 35 | public applyModelInValue() { 36 | const value = Common.get(Common.getScope(this.element).scope, this.attribute); 37 | switch (this.element.type) { 38 | case 'date': 39 | if (this.element.valueAsDate && this.element.valueAsDate.getTime() !== value.getTime()) { 40 | this.element.valueAsDate = value || null; 41 | } 42 | break; 43 | case 'number': 44 | if (value !== this.element.valueAsNumber && value !== undefined) { 45 | this.element.valueAsNumber = value || null; 46 | } 47 | break; 48 | default: 49 | if (this.element.value !== value) { 50 | this.element.value = value || null; 51 | } 52 | } 53 | } 54 | 55 | public applyValueInModel(evt) { 56 | const self = (evt ? (evt.target || evt.srcElement) : this.element)['cpModel']; 57 | switch (self.element.type) { 58 | case 'date': 59 | Common.set(Common.getScope(self.element).scope, self.attribute, self.element.valueAsDate); 60 | break; 61 | case 'number': 62 | Common.set(Common.getScope(self.element).scope, self.attribute, isNaN(self.element.valueAsNumber) ? undefined : self.element.valueAsNumber); 63 | break; 64 | default: 65 | Common.set(Common.getScope(self.element).scope, self.attribute, self.element.value); 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/map/directive/cp-mouse.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPMouse implements Directive { 7 | 8 | private readonly element: any; 9 | private map: MapDom; 10 | private attributes; 11 | 12 | constructor(_element: HTMLElement, _map: MapDom) { 13 | this.element = _element; 14 | this.attributes = []; 15 | this.map = _map; 16 | Array.from(this.element.attributes).forEach((attribute: any) => { 17 | if (attribute.nodeName && attribute.nodeName.startsWith(Constants.MOUSE_ATTRIBUTE_NAME)) { 18 | if (!attribute.value) { 19 | throw new Error(`syntax error ${Constants.MOUSE_ATTRIBUTE_NAME} expected arguments`); 20 | } 21 | this.element[attribute.name] = this; 22 | this.attributes.push(attribute.name); 23 | } 24 | }); 25 | } 26 | 27 | public create() { 28 | this.init(); 29 | } 30 | 31 | public onMouse(evt) { 32 | const directiveName = 'cp-' + evt.type; 33 | if (evt.target && evt.target[directiveName]) { 34 | Common.executeFunctionCallback(evt.target[directiveName].element, evt.target[directiveName].element.getAttribute(directiveName), { [Constants.EVENT_ATTRIBUTE_NAME] : evt }); 35 | } 36 | } 37 | 38 | public init() { 39 | this.attributes.forEach((attribute) => { 40 | const indexSeparator = attribute.lastIndexOf('.'); 41 | const eventType = attribute.substring(0, (indexSeparator === -1 ? attribute.length : indexSeparator)).replace(Constants.MOUSE_ATTRIBUTE_NAME, ''); 42 | // Remove old event 43 | this.element.removeEventListener(`mouse${eventType}`, (evt) => this.onMouse(evt)); 44 | // Add new event 45 | this.element.addEventListener(`mouse${eventType}`, this.onMouse); 46 | }); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/map/directive/cp-repeat.ts: -------------------------------------------------------------------------------- 1 | import isEqual from 'lodash.isequal'; 2 | import { Common } from '../../common'; 3 | import { Constants } from '../../constants'; 4 | import { Controller } from '../../core/controller'; 5 | import capivara from '../../index'; 6 | import { MapDom } from '../map-dom'; 7 | import { Directive } from './directive.interface'; 8 | 9 | export class CPRepeat implements Directive { 10 | 11 | private readonly attribute; 12 | private readonly originalElement; 13 | private readonly referenceNode; 14 | private readonly regex; 15 | private map: MapDom; 16 | private element; 17 | private lastArray = []; 18 | private elms = []; 19 | private attributeAlias; 20 | private attributeScope; 21 | 22 | constructor(_element: HTMLElement, _map: MapDom) { 23 | this.element = _element.cloneNode(true); 24 | this.element.removeAttribute(Constants.REPEAT_ATTRIBUTE_NAME); 25 | this.element.classList.add('binding-repeat'); 26 | this.originalElement = _element; 27 | this.map = _map; 28 | this.attribute = _element.getAttribute(Constants.REPEAT_ATTRIBUTE_NAME).replace(/\s+/g, ' '); 29 | this.regex = new RegExp('^[\\s*|\\S]+\\s+' + Constants.REPEAT_ATTRIBUTE_OPERATOR.replace(/ /g, '') + '\\s+\\S+\\s*', 'g'); 30 | const matches = this.attribute.match(this.regex); 31 | if (!this.attribute || (!matches || matches.length === 0)) { 32 | throw new Error(`syntax error invalid ${Constants.REPEAT_ATTRIBUTE_NAME} expresion: ${this.attribute}`); 33 | } 34 | this.referenceNode = document.createComment('start repeat ' + this.attribute); 35 | if (this.originalElement.parentNode.replaceChild) { 36 | this.originalElement.parentNode.replaceChild(this.referenceNode, this.originalElement); 37 | } 38 | } 39 | 40 | public create() { 41 | const operator = ` ${Constants.REPEAT_ATTRIBUTE_OPERATOR} `; 42 | this.attributeAlias = this.attribute.substring(0, this.attribute.indexOf(operator)).replace(/ /g, ''); 43 | this.attributeScope = this.attribute.substring(this.attribute.indexOf(operator) + operator.length, this.attribute.length).replace(/ /g, ''); 44 | this.applyLoop(); 45 | } 46 | 47 | public applyLoop() { 48 | const array = Common.evalInMultiContext(this.originalElement, this.attributeScope); 49 | if (array && !isEqual(array, this.lastArray)) { 50 | this.lastArray = array.slice(); 51 | this.removeChildes(); 52 | this.loop(array, this.attributeAlias); 53 | } 54 | } 55 | 56 | public removeChildes() { 57 | this.elms.forEach((elm) => this.referenceNode.parentNode.removeChild(elm)); 58 | } 59 | 60 | public loop(array, attributeAlias) { 61 | this.elms = []; // reset elements render 62 | let lastAdded = this.referenceNode; 63 | 64 | array.forEach((row, index) => { 65 | const elm = this.element.cloneNode(true); 66 | new Controller(elm, () => { }); 67 | Common.appendAfter(lastAdded, elm); 68 | const elementContext = Common.getScope(elm); 69 | elementContext.scope[attributeAlias] = row; 70 | elementContext.scope[Constants.REPEAT_INDEX_NAME] = index; 71 | elementContext.$parent = Common.getScope(this.referenceNode.parentNode); 72 | this.createChildrenComponents(elm); 73 | lastAdded = elm; 74 | this.elms.push(elm); // add element reference. 75 | }); 76 | 77 | if (lastAdded) { 78 | Common.appendAfter(lastAdded, this.referenceNode.parentNode.appendChild(document.createComment('end repeat ' + this.attribute))); 79 | } 80 | } 81 | 82 | private createChildrenComponents(elm) { 83 | (Array.from(elm.children) || []).forEach((child) => { 84 | capivara.constroyIfComponent(child); 85 | }); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/map/directive/cp-show.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { Constants } from '../../constants'; 3 | import { MapDom } from '../map-dom'; 4 | import { Directive } from './directive.interface'; 5 | 6 | export class CPShow implements Directive { 7 | 8 | private readonly element: any; 9 | private readonly attribute; 10 | private readonly initialDisplay; 11 | private map: MapDom; 12 | 13 | constructor(_element: HTMLElement, _map: MapDom) { 14 | this.element = _element; 15 | this.initialDisplay = this.element.style.display || ''; 16 | this.map = _map; 17 | this.attribute = Common.getAttributeCpShow(this.element); 18 | if (!this.attribute) { 19 | throw new Error(`syntax error ${Constants.SHOW_ATTRIBUTE_NAME} expected arguments`); 20 | } 21 | } 22 | 23 | public create() { 24 | this.init(); 25 | } 26 | 27 | public init() { 28 | try { 29 | Common.isValidCondition(this.element, Common.getAttributeCpShow(this.element)) ? this.show() : this.hide(); 30 | } catch (ex) { 31 | this.hide(); 32 | } 33 | } 34 | 35 | public hide() { 36 | this.element.style.display = 'none'; 37 | } 38 | 39 | public show() { 40 | this.element.style.display = this.initialDisplay; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/map/directive/cp-style.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../../common'; 2 | import { MapDom } from '../map-dom'; 3 | import { Directive } from './directive.interface'; 4 | 5 | export class CPStyle implements Directive { 6 | 7 | private readonly element: any; 8 | private readonly attribute; 9 | private map: MapDom; 10 | private elementComment; 11 | private elmScope; 12 | 13 | constructor(_element: HTMLElement, _map: MapDom) { 14 | this.element = _element; 15 | this.element['cpStyle'] = this; 16 | this.map = _map; 17 | this.attribute = Common.getAttributeCpStyle(this.element); 18 | this.elementComment = document.createComment('cpStyle ' + this.attribute); 19 | this.elmScope = Common.getScope(_element); 20 | } 21 | 22 | public create() { 23 | this.init(); 24 | } 25 | 26 | public setStyleByObject(style) { 27 | if (style && window['capivara'].isObject(style)) { 28 | Object.keys(style).forEach((key) => { 29 | this.element.style.setProperty(key.replace(/ /g, ''), style[key]); 30 | }); 31 | } 32 | } 33 | 34 | public init() { 35 | try { 36 | this.attribute.split(',') 37 | .map((attr) => { 38 | return { 39 | key: attr.substring(0, attr.indexOf(':')).replace(/'/g, "").replace(/"/, '').replace(/{/g, '').replace(/}/, ''), 40 | value: Common.evalInMultiContext(this.element, attr.substring(attr.indexOf(':') + 1, attr.length).replace(/{/g, '').replace(/}/, '')), 41 | }; 42 | }) 43 | .forEach((style) => { 44 | if (window['capivara'].isString(style.value)) { 45 | this.element.style.setProperty(style.key.replace(/ /g, ''), style.value); 46 | } else { 47 | this.setStyleByObject(style.value); 48 | } 49 | }); 50 | } catch (e) { 51 | this.setStyleByObject(Common.executeFunctionCallback(this.element, this.attribute)); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/map/directive/directive.interface.ts: -------------------------------------------------------------------------------- 1 | export interface Directive { 2 | create(_element?); 3 | } 4 | -------------------------------------------------------------------------------- /src/scope/scope.proxy.ts: -------------------------------------------------------------------------------- 1 | import { Constants } from '../constants'; 2 | import { Observe } from '../core/observer'; 3 | import { MapDom } from '../map/map-dom'; 4 | import { Scope } from './scope'; 5 | 6 | export class ScopeProxy { 7 | 8 | public mapDom: MapDom; 9 | public element: HTMLElement; 10 | 11 | constructor(_scope: Scope, _mapDom: MapDom, _element: HTMLElement) { 12 | this.mapDom = _mapDom; 13 | this.element = _element; 14 | this.createWatcherScope(_scope, this); 15 | } 16 | 17 | public createWatcherScope(scope, objectObserve) { 18 | if (this.element['$instance']) { 19 | scope.$on('$onInit', () => { 20 | Observe.observe(objectObserve[this.element['$instance'].config.controllerAs], (changes) => { 21 | if (changes.length > 0) { 22 | this.updateScopes(objectObserve.element[Constants.SCOPE_ATTRIBUTE_NAME]); 23 | } 24 | scope.$emit('$onChanges', changes); 25 | this.executeObservers(objectObserve, '$onChanges', changes); 26 | this.executeObservers(objectObserve, '_$$checkBindings', changes); 27 | }); 28 | }); 29 | } 30 | } 31 | 32 | private updateScopes(scope: Scope) { 33 | if (!scope.$parent) { 34 | scope.mapDom.reload(); 35 | } else { 36 | this.updateScopes(scope.$parent); 37 | } 38 | } 39 | 40 | private executeObservers(objectObserve, observeName, changes) { 41 | if (objectObserve[this.element['$instance'].config.controllerAs][observeName]) { 42 | objectObserve[this.element['$instance'].config.controllerAs][observeName](changes); 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/scope/scope.ts: -------------------------------------------------------------------------------- 1 | import { Common } from '../common'; 2 | import { Constants } from '../constants'; 3 | import { CapivaraElement } from '../core/element'; 4 | import { Eval } from '../core/eval'; 5 | import { MapDom } from '../map/map-dom'; 6 | import { ScopeProxy } from './scope.proxy'; 7 | 8 | export class Scope { 9 | 10 | // Dados disponíveis nesse escopo 11 | public scope: ScopeProxy; 12 | 13 | public $parent: Scope; 14 | 15 | public mapDom: MapDom; 16 | 17 | public watchers; 18 | 19 | public observers; 20 | 21 | public id; 22 | 23 | private cpElements = {}; 24 | 25 | constructor(_element: HTMLElement) { 26 | if (!_element || !_element.nodeName) { 27 | console.warn('Unable to create a scope, it is necessary to report an html element.'); 28 | } 29 | Common.setScopeId(this); 30 | this.watchers = []; 31 | Scope.addScope(_element, this); 32 | this.mapDom = new MapDom(_element); 33 | this.scope = new ScopeProxy(this, this.mapDom, _element); 34 | if (!_element['$instance']) { 35 | this.$emit('$onInit'); 36 | } 37 | this.observers = []; 38 | this.$on('$onChanges', this.onChanges); 39 | if (_element && _element.parentNode && _element.parentNode[Constants.SCOPE_ATTRIBUTE_NAME]) { 40 | this.$parent = _element.parentNode[Constants.SCOPE_ATTRIBUTE_NAME]; 41 | } 42 | } 43 | 44 | public getScopeProxy() { 45 | return this.scope; 46 | } 47 | 48 | /** #Mudar não poderia ser adicionar a referencia do scope do componente no elemento do componente 49 | * @method void Aplicado um escopo em um elemento HTML. 50 | * @param element Elemento que será aplicado o escopo 51 | * @param scope Escopo que será aplicado no elemento 52 | */ 53 | public static addScope(element: any, scope: Scope) { 54 | if (element && element.nodeName) { element[Constants.SCOPE_ATTRIBUTE_NAME] = scope; } 55 | } 56 | 57 | public $on = (evtName, callback) => { 58 | this.watchers.push({ evtName, callback }); 59 | } 60 | 61 | public $emit = (evtName, ...args) => { 62 | this.watchers 63 | .filter((watcher) => watcher.evtName === evtName) 64 | .forEach((watcher) => { 65 | watcher.callback.call(this, ...args); 66 | }); 67 | } 68 | 69 | public $eval = (source) => { 70 | return Eval.exec(this.scope, source); 71 | } 72 | 73 | public onChanges(changes) { 74 | this.observers.forEach((observer) => { 75 | changes.filter((change) => change.type === 'update' && change.name === observer.key).forEach((change) => { 76 | observer.callback.call(observer.ctx, change.object[change.name], change.oldValue); 77 | }); 78 | }); 79 | } 80 | 81 | public $watch(key: string, callback?, ctx?) { 82 | this.observers.push({ 83 | key, 84 | callback, 85 | ctx, 86 | }); 87 | } 88 | 89 | public $unwatch(key: string, callback) { 90 | this.observers = this.observers.filter((observer) => observer.key !== key); 91 | } 92 | 93 | public element(element) { 94 | if (this.cpElements[element] && this.cpElements[element].element === element) { 95 | return this.cpElements[element]; 96 | } 97 | const capivaraElement = new CapivaraElement(element); 98 | this.cpElements[element] = capivaraElement; 99 | return capivaraElement; 100 | } 101 | 102 | public destroy() { 103 | Object.keys(this.cpElements).forEach((key) => { 104 | this.cpElements[key].destroy(); 105 | }); 106 | } 107 | 108 | public refresh() { 109 | this.mapDom.reload(); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /test/e2e/cpBlur/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 34 | 35 | -------------------------------------------------------------------------------- /test/e2e/cpBlur/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpBlur': function(browser){ 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpBlur/template.html') 6 | .assert.containsText('h1', 'False') 7 | .pause(1000) 8 | .click('input') 9 | .click('h1') 10 | .pause(500) 11 | .assert.containsText('h1', 'True') 12 | .pause(500) 13 | .end(); 14 | } 15 | }; -------------------------------------------------------------------------------- /test/e2e/cpChange/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /test/e2e/cpChange/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpChange' : function(browser){ 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpChange/template.html') 6 | .waitForElementVisible('input', 10000) 7 | .pause(1000) 8 | .setValue('input[cp-model="$ctrl.var"]', ' world') 9 | .pause(1000) 10 | .setValue('input[cp-model="$ctrl.var2"]', ' =)') 11 | .pause(1000) 12 | .assert.containsText('#first', '6') 13 | .assert.containsText('#second', '3') 14 | .pause(1000) 15 | .end(); 16 | } 17 | }; -------------------------------------------------------------------------------- /test/e2e/cpClass/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 21 | 22 | 23 | 24 | 25 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /test/e2e/cpClass/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpClass': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpClass/template.html') 6 | .waitForElementVisible('body', 10000) 7 | .waitForElementVisible('p#p1', 10000) 8 | .pause(1000) 9 | .click('button#btn1') 10 | .pause(1500) 11 | .waitForElementVisible('p#p1.democlass', 2000) 12 | .waitForElementVisible('p#p2', 10000) 13 | .pause(1000) 14 | .click('button#btn2') 15 | .pause(1500) 16 | .waitForElementVisible('p#p2.democlass2', 2000) 17 | .pause(1000) 18 | .end(); 19 | } 20 | }; -------------------------------------------------------------------------------- /test/e2e/cpClick/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 31 | 32 | -------------------------------------------------------------------------------- /test/e2e/cpClick/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpClick': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpClick/template.html') 6 | .waitForElementVisible('button', 10000) 7 | .pause(1000) 8 | .assert.containsText('button', 'Click me') 9 | .click('button') 10 | .pause(1000) 11 | .assert.containsText('button', 'Clicked') 12 | .pause(1000) 13 | .end(); 14 | } 15 | }; -------------------------------------------------------------------------------- /test/e2e/cpDisabled/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 32 | 33 | -------------------------------------------------------------------------------- /test/e2e/cpDisabled/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpDisable': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpDisabled/template.html') 6 | .waitForElementVisible('button', 10000) 7 | .pause(1000) 8 | .assert.containsText('button', 'Click me') 9 | .click('button') 10 | .pause(1000) 11 | .assert.containsText('button', 'Click me') 12 | .pause(1000) 13 | .end(); 14 | } 15 | }; -------------------------------------------------------------------------------- /test/e2e/cpDoubleClick/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 30 | 31 | -------------------------------------------------------------------------------- /test/e2e/cpDoubleClick/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpDoubleClick': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpDoubleClick/template.html') 6 | .waitForElementVisible('button', 10000) 7 | .pause(1000) 8 | .moveToElement('button', 10, 10) 9 | .doubleClick() 10 | .pause(1000) 11 | .assert.containsText('button', 'Double Clicked') 12 | .pause(1000) 13 | .end(); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /test/e2e/cpElse/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/e2e/cpElse/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpElse': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpElse/template.html') 6 | .waitForElementVisible('button', 10000) 7 | .pause(1000) 8 | .assert.containsText('button', 'Click to show!') 9 | .click('button') 10 | .pause(1000) 11 | .assert.containsText('h1', 'This is an other text.') 12 | .pause(1000) 13 | .end(); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /test/e2e/cpElseIf/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 36 | 37 | -------------------------------------------------------------------------------- /test/e2e/cpElseIf/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpElseIf': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpElseIf/template.html') 6 | .waitForElementVisible('button', 10000) 7 | .pause(1000) 8 | .assert.containsText('h1','H1 with ELSE has the sum equal to 1.') 9 | .click('button') 10 | .pause(1000) 11 | .assert.containsText('h1', 'H1 with IF has the sum equal to 2.') 12 | .click('button') 13 | .pause(1000) 14 | .assert.containsText('h1', 'H1 with ELSE IF has the sum equal to 3.') 15 | .pause(1000) 16 | .end(); 17 | } 18 | }; -------------------------------------------------------------------------------- /test/e2e/cpFocus/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 34 | 35 | -------------------------------------------------------------------------------- /test/e2e/cpFocus/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpFocus': function(browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpFocus/template.html') 6 | .assert.containsText('h1', 'Input not Focused') 7 | .pause(1000) 8 | .click('input') 9 | .assert.containsText('h1', 'Input focused') 10 | .pause(500) 11 | .end(); 12 | } 13 | }; -------------------------------------------------------------------------------- /test/e2e/cpHide/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/e2e/cpHide/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpHide': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpHide/template.html') 6 | .waitForElementVisible('div', 10000) 7 | .pause(1000) 8 | .expect.element('div').to.have.css('display').which.contains(''); 9 | browser 10 | .setValue('input', 'red') 11 | .pause(1000) 12 | .expect.element('div').to.have.css('display').which.contains('none'); 13 | browser 14 | .pause(500) 15 | .end(); 16 | } 17 | }; -------------------------------------------------------------------------------- /test/e2e/cpIf/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 33 | 34 | -------------------------------------------------------------------------------- /test/e2e/cpIf/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpIf': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpIf/template.html') 6 | .waitForElementVisible('button', 10000) 7 | .waitForElementNotPresent('h1', 1000) 8 | .pause(1000) 9 | .click('button') 10 | .pause(1000) 11 | .assert.containsText('h1', 'This is a simple text.') 12 | .pause(1000) 13 | .end(); 14 | } 15 | }; -------------------------------------------------------------------------------- /test/e2e/cpInit/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 35 | 36 | -------------------------------------------------------------------------------- /test/e2e/cpInit/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpInit': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpInit/template.html') 6 | .waitForElementVisible('h1', 10000) 7 | .assert.containsText('h1', 'CpInit Test') 8 | .pause(5000) 9 | .assert.containsText('h1', 'CpInit complete') 10 | .end(); 11 | } 12 | }; -------------------------------------------------------------------------------- /test/e2e/cpKey/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /test/e2e/cpKey/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpKey': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpKey/template.html') 6 | .waitForElementVisible('input', 10000) 7 | .pause(1000) 8 | .setValue('input', ' Capivara') 9 | .pause(1000) 10 | .sendKeys('button', browser.Keys.ENTER) 11 | .assert.containsText('p', 'Mateus Capivara') 12 | .end(); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /test/e2e/cpMax/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/e2e/cpMax/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpMax': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpMax/template.html') 6 | .waitForElementVisible('input', 10000) 7 | .pause(1000) 8 | .click('input'); 9 | for (let i = 0; i < 10; i++) { 10 | browser 11 | .sendKeys('input', browser.Keys.RIGHT_ARROW); 12 | } 13 | browser 14 | .pause(1000) 15 | .assert.containsText('h1', '5') 16 | .pause(1000) 17 | .end(); 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /test/e2e/cpMaxLength/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/e2e/cpMaxLength/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpMaxLength': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpMaxLength/template.html') 6 | .waitForElementVisible('input', 10000) 7 | .pause(1000) 8 | .assert.containsText('p', 'Capivara') 9 | .setValue('input', ' JS') 10 | .pause(1500) 11 | .assert.containsText('p', 'Capivara J') 12 | .end(); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /test/e2e/cpMin/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/e2e/cpMin/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpMin': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpMin/template.html') 6 | .waitForElementVisible('input', 10000) 7 | .pause(1000) 8 | .click('input'); 9 | for (let i = 0; i < 100; i++) { 10 | browser 11 | .sendKeys('input', browser.Keys.DOWN_ARROW); 12 | } 13 | browser 14 | .assert.containsText('h1', '0') 15 | .pause(1000) 16 | .end(); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /test/e2e/cpModel/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Test 8 | 9 | 10 | 11 | 12 | 13 | 14 | 35 | 36 | -------------------------------------------------------------------------------- /test/e2e/cpModel/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpModel': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpModel/template.html') 6 | .waitForElementVisible('p', 10000) 7 | .pause(1000) 8 | .assert.containsText('p', 'Capivara') 9 | .setValue('input', ' JS') 10 | .pause(1500) 11 | .assert.containsText('p', 'Capivara JS') 12 | .end(); 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /test/e2e/cpMouse/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /test/e2e/cpMouse/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpMouse': function(browser){ 3 | browser 4 | .resizeWindow(1920, 1020) 5 | .url('http://localhost:1111/test/e2e/cpMouse/template.html') 6 | .waitForElementVisible('input', 5000) 7 | .pause(3000) 8 | .moveToElement('input', 10, 10) 9 | .pause(1000) 10 | .assert.containsText('h1', 'mousein') 11 | .pause(1000) 12 | .moveToElement('body', 100, 100) 13 | .pause(1000) 14 | .assert.containsText('h1', 'mouseout') 15 | .pause(1000) 16 | .end(); 17 | } 18 | }; -------------------------------------------------------------------------------- /test/e2e/cpPlaceholder/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | 13 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/e2e/cpPlaceholder/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpPlaceholder': function(browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpPlaceholder/template.html') 6 | .pause(1000) 7 | .expect.element('input').to.have.attribute('placeholder').which.contains('Capivara'); 8 | browser 9 | .click('button') 10 | .pause(1000) 11 | .expect.element('input').to.have.attribute('placeholder').which.contains('CapivaraJS'); 12 | browser.pause(2000); 13 | }, 14 | }; -------------------------------------------------------------------------------- /test/e2e/cpRepeat/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/e2e/cpRepeat/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpRepeat': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpRepeat/template.html') 6 | .waitForElementVisible('button', 10000) 7 | .pause(1000) 8 | .assert.containsText('li:nth-child(1) p', 'John') 9 | .assert.containsText('li:nth-child(2) p', 'Bob') 10 | .click('button') 11 | .pause(1000) 12 | .assert.containsText('li:nth-child(3) p', 'Anna') 13 | .end(); 14 | } 15 | }; -------------------------------------------------------------------------------- /test/e2e/cpShow/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /test/e2e/cpShow/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpShow': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpShow/template.html') 6 | .waitForElementVisible('button', 10000) 7 | .pause(1000) 8 | .expect.element('h1').to.have.css('display').which.contains('none'); 9 | browser 10 | .click('button') 11 | .pause(1000) 12 | .expect.element('h1').to.have.css('display').which.contains(''); 13 | browser.end(); 14 | } 15 | }; -------------------------------------------------------------------------------- /test/e2e/cpSrc/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/e2e/cpSrc/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpSrc': function (browser) { 3 | browser.resizeWindow(1920, 1080); 4 | browser 5 | .url('http://localhost:1111/test/e2e/cpSrc/template.html') 6 | .pause(1500) 7 | .waitForElementVisible('img[src="https://avatars1.githubusercontent.com/u/33517395?s=200&v=4"]', 3000) 8 | .pause(1000) 9 | .click('button[cp-click="$ctrl.click()"]') 10 | .pause(5000) 11 | .waitForElementVisible('img[src="https://bit.ly/2pTjZnU"]', 20000) 12 | .pause(3000) 13 | .end(); 14 | } 15 | }; -------------------------------------------------------------------------------- /test/e2e/cpStep/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/e2e/cpStep/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpStep': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpStep/template.html') 6 | .waitForElementVisible('input', 10000) 7 | .pause(1000) 8 | .click('input'); 9 | for (let i = 0; i < 10; i++) { 10 | browser 11 | .sendKeys('input', browser.Keys.UP_ARROW); 12 | } 13 | browser 14 | .assert.containsText('h1', '30') 15 | .pause(1000) 16 | .end(); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /test/e2e/cpStyle/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /test/e2e/cpStyle/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'cpStyle': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/cpStyle/template.html') 6 | .pause(1000) 7 | .waitForElementVisible('h1', 10000) 8 | .assert.cssProperty('h1', 'color', 'rgba(0, 128, 0, 1)') 9 | .pause(1000) 10 | .click('button[id="btn1"]') 11 | .pause(1000) 12 | .assert.cssProperty('h1', 'color', 'rgba(255, 0, 0, 1)') 13 | .pause(1000) 14 | .expect.element('p#p1').to.have.css('background').which.contains('rgb(0, 0, 255)'); 15 | browser 16 | .pause(1000) 17 | .click('button[id="btn2"]') 18 | .pause(1000) 19 | .expect.element('p#p1').to.have.css('background').which.contains('rgb(128, 128, 128)'); 20 | browser 21 | .pause(1000) 22 | .click('button[id="btn3"]') 23 | .pause(1000) 24 | .expect.element('p#p3').to.have.css('background').which.contains('rgb(0, 128, 0)'); 25 | browser 26 | .pause(1000) 27 | .end(); 28 | } 29 | }; -------------------------------------------------------------------------------- /test/e2e/index.js: -------------------------------------------------------------------------------- 1 | module.exports = Object.assign( 2 | require('./cpModel/test'), 3 | require('./cpClick/test'), 4 | require('./cpKey/test'), 5 | require('./cpChange/test'), 6 | require('./cpDoubleClick/test'), 7 | require('./cpMouse/test'), 8 | require('./cpPlaceholder/test'), 9 | require('./cpClass/test'), 10 | require('./cpElse/test'), 11 | require('./cpElseIf/test'), 12 | require('./cpIf/test'), 13 | require('./cpInit/test'), 14 | require('./cpRepeat/test'), 15 | require('./cpShow/test'), 16 | require('./cpSrc/test'), 17 | require('./cpStyle/test'), 18 | require('./interpolation/test'), 19 | require('./noBind/test'), 20 | require('./cpDisabled/test'), 21 | require('./cpMax/test'), 22 | require('./cpMin/test'), 23 | require('./cpStep/test'), 24 | require('./cpMaxLength/test'), 25 | require('./cpDisabled/test'), 26 | require('./cpFocus/test'), 27 | require('./cpHide/test'), 28 | require('./cpBlur/test') 29 | ); 30 | -------------------------------------------------------------------------------- /test/e2e/interpolation/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /test/e2e/interpolation/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'interpolation': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/interpolation/template.html') 6 | .pause(1000) 7 | .waitForElementVisible('h1', 10000) 8 | .pause(1000) 9 | .click('button') 10 | .pause(1000) 11 | .assert.containsText('h1', 'felipe2') 12 | .assert.containsText('h2', 'felipe') 13 | .end(); 14 | } 15 | }; -------------------------------------------------------------------------------- /test/e2e/noBind/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Test 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/e2e/noBind/test.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'noBind': function (browser) { 3 | browser 4 | .resizeWindow(1920, 1080) 5 | .url('http://localhost:1111/test/e2e/noBind/template.html') 6 | .pause(1000) 7 | .waitForElementVisible('div', 10000) 8 | .pause(1000) 9 | .assert.containsText('div h2', '[[2+2]]') 10 | .assert.containsText('h1', '4') 11 | .end(); 12 | } 13 | }; -------------------------------------------------------------------------------- /test/spec/capivara-change.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test of click without parameters', () => { 5 | const template = ` 6 | 7 | 8 | `; 9 | const element = document.createElement('div'); 10 | element.innerHTML = template; 11 | capivara.controller(element, function() { 12 | const $ctrl = this; 13 | 14 | $ctrl.$onInit = () => { 15 | $ctrl.clicked = false; 16 | }; 17 | 18 | $ctrl.toggleClicked = () => { 19 | $ctrl.clicked = !$ctrl.clicked; 20 | }; 21 | 22 | $ctrl.$onViewInit = () => { 23 | it('The value of the variable must be true', () => { 24 | element.querySelector('button').click(); 25 | expect(element['$instance'].componentScope.$ctrl.clicked).toEqual(true); 26 | }); 27 | }; 28 | }); 29 | }); 30 | 31 | describe('test of click with parameters method sum', () => { 32 | const template = ` 33 | 34 | 35 | 36 | `; 37 | const element = document.createElement('div'); 38 | element.innerHTML = template; 39 | 40 | capivara.controller(element, function() { 41 | const $ctrl = this; 42 | 43 | $ctrl.$onInit = () => { 44 | $ctrl.numberOne = 90; 45 | $ctrl.numberTwo = 10; 46 | }; 47 | 48 | $ctrl.sum = (value) => { 49 | $ctrl.result = value; 50 | }; 51 | 52 | $ctrl.$onViewInit = () => { 53 | it('Must be the sum of the two numbers', () => { 54 | element.querySelector('button').click(); 55 | expect(element['$instance'].componentScope.$ctrl.result).toEqual(100); 56 | }); 57 | }; 58 | 59 | }); 60 | 61 | }); 62 | 63 | describe('test of click with parameters method subtract', () => { 64 | const template = ` 65 | 66 | 67 | 68 | `; 69 | const element = document.createElement('div'); 70 | element.innerHTML = template; 71 | 72 | capivara.controller(element, function() { 73 | const $ctrl = this; 74 | 75 | $ctrl.$onInit = () => { 76 | $ctrl.numberOne = 90; 77 | $ctrl.numberTwo = 10; 78 | }; 79 | 80 | $ctrl.subtract = (value) => { 81 | $ctrl.result = value; 82 | }; 83 | 84 | $ctrl.$onViewInit = () => { 85 | it('Must be the subtraction of the two numbers', () => { 86 | element.querySelector('button').click(); 87 | expect(element['$instance'].componentScope.$ctrl.result).toEqual(80); 88 | }); 89 | }; 90 | }); 91 | }); 92 | 93 | describe('test of click with parameters object', () => { 94 | const template = ` 95 | 96 | `; 97 | const element = document.createElement('div'); 98 | element.innerHTML = template; 99 | 100 | capivara.controller(element, function() { 101 | const $ctrl = this; 102 | 103 | $ctrl.$onInit = () => { 104 | $ctrl.person = { 105 | name: 'Mateus', 106 | }; 107 | }; 108 | 109 | $ctrl.save = (person) => { 110 | $ctrl.result = person; 111 | }; 112 | 113 | $ctrl.$onViewInit = () => { 114 | it('Must be the same object', () => { 115 | element.querySelector('button').click(); 116 | expect(element['$instance'].componentScope.$ctrl.result).toEqual(element['$instance'].componentScope.$ctrl.person); 117 | }); 118 | }; 119 | 120 | }); 121 | }); 122 | 123 | describe('test methods', () => { 124 | const template = ` 125 | 126 | `; 127 | const element = document.createElement('div'); 128 | element.innerHTML = template; 129 | capivara.controller(element, function() { 130 | const $ctrl = this; 131 | 132 | $ctrl.save = function() { 133 | $ctrl.clicked = true; 134 | }; 135 | 136 | $ctrl.$onViewInit = () => { 137 | const cpClick = new CPClick(element.querySelector('button'), null); 138 | it('Should create the click event', (done) => { 139 | cpClick.create(); 140 | element.querySelector('button').click(); 141 | setTimeout(() => { 142 | expect(element.querySelector('button')['$scope'].scope.$ctrl.clicked).toEqual(true); 143 | done(); 144 | }, 1000); 145 | }); 146 | }; 147 | 148 | }); 149 | }); 150 | -------------------------------------------------------------------------------- /test/spec/capivara-component-instance.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | // describe('test create component', () => { 5 | // const template = ` 6 | // 7 | // `; 8 | // const element = document.createElement('div'); 9 | // element.innerHTML = template; 10 | // }); 11 | -------------------------------------------------------------------------------- /test/spec/capivara-component.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test create component', () => { 5 | const template = ` 6 | 7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | document.body.appendChild(element); 11 | const config = { 12 | template: '

Hello World

', 13 | }; 14 | capivara.component('my-component', config); 15 | it("Expected config equal", function() { 16 | expect(capivara.components['MY-COMPONENT'].config.template).toEqual(config.template); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/spec/capivara-disabled.spec.ts: -------------------------------------------------------------------------------- 1 | import {} from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('Directive cp-disabled', () => { 5 | 6 | it('Should check if disable is truth', () => { 7 | const template = ``; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | const $ctrl = this; 12 | 13 | $ctrl.$onInit = () => { 14 | $ctrl.clicked = 0; 15 | }; 16 | 17 | $ctrl.addOne = () => { 18 | $ctrl.clicked += 1; 19 | }; 20 | 21 | $ctrl.$onViewInit = () => { 22 | element.querySelector('button').click(); 23 | expect(element['$instance'].componentScope.$ctrl.clicked).toEqual(0); 24 | }; 25 | }); 26 | }); 27 | 28 | it('Should check if disable is false', () => { 29 | const template = ``; 30 | const element = document.createElement('div'); 31 | element.innerHTML = template; 32 | capivara.controller(element, function() { 33 | const $ctrl = this; 34 | 35 | $ctrl.$onInit = () => { 36 | $ctrl.clicked = 0; 37 | }; 38 | 39 | $ctrl.addOne = () => { 40 | $ctrl.clicked += 1; 41 | }; 42 | 43 | $ctrl.$onViewInit = () => { 44 | setTimeout(function() { 45 | element.querySelector('button').click(); 46 | expect(element['$instance'].componentScope.$ctrl.clicked).toEqual(1); 47 | }, 0); 48 | }; 49 | 50 | }); 51 | }); 52 | 53 | it('Should update disable value changed', () => { 54 | const template = ``; 55 | const element = document.createElement('div'); 56 | element.innerHTML = template; 57 | capivara.controller(element, function() { 58 | const $ctrl = this; 59 | $ctrl.$onInit = () => { 60 | $ctrl.clicked = false; 61 | }; 62 | $ctrl.$onViewInit = () => { 63 | setTimeout(function() { 64 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(false); 65 | element['$instance'].componentScope.$ctrl.clicked = true; 66 | }, 0); 67 | setTimeout(function() { 68 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(true); 69 | element['$instance'].componentScope.$ctrl.clicked = false; 70 | }, 0); 71 | setTimeout(function() { 72 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(false); 73 | element['$instance'].componentScope.$ctrl.clicked = true; 74 | }, 0); 75 | setTimeout(function() { 76 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(true); 77 | element['$instance'].componentScope.$ctrl.clicked = null; 78 | }, 0); 79 | setTimeout(function() { 80 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(false); 81 | element['$instance'].componentScope.$ctrl.clicked = undefined; 82 | }, 0); 83 | setTimeout(function() { 84 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(false); 85 | element['$instance'].componentScope.$ctrl.clicked = {}; 86 | }, 0); 87 | setTimeout(function() { 88 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(false); 89 | element['$instance'].componentScope.$ctrl.clicked = []; 90 | }, 0); 91 | setTimeout(function() { 92 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(false); 93 | element['$instance'].componentScope.$ctrl.clicked = 0; 94 | }, 0); 95 | setTimeout(function() { 96 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(false); 97 | element['$instance'].componentScope.$ctrl.clicked = 1; 98 | }, 0); 99 | setTimeout(function() { 100 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(true); 101 | element['$instance'].componentScope.$ctrl.clicked = 0; 102 | }, 0); 103 | setTimeout(function() { 104 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(false); 105 | element['$instance'].componentScope.$ctrl.clicked = 1; 106 | }, 0); 107 | setTimeout(function() { 108 | expect(element.querySelector('button').hasAttribute('disabled')).toEqual(true); 109 | }, 0); 110 | }; 111 | }); 112 | }); 113 | }); 114 | -------------------------------------------------------------------------------- /test/spec/capivara-doubleclick.spec.ts: -------------------------------------------------------------------------------- 1 | // import {} from 'jasmine'; 2 | // import capivara from '../../src/index'; 3 | // import {CPClick} from '../../src/map/directive/cp-click'; 4 | 5 | // function triggerDoubeClick(element) { 6 | // const doubleClickEvent = document.createEvent('MouseEvents'); 7 | // doubleClickEvent.initEvent('dblclick', true, true); 8 | // element.querySelector('button').dispatchEvent(doubleClickEvent); 9 | // } 10 | 11 | // describe('Directive cp-dblclick', () => { 12 | 13 | // it('The value of the variable must be true', () => { 14 | // const template = ` 15 | // 16 | // `; 17 | // const element = document.createElement('div'); 18 | // element.innerHTML = template; 19 | // capivara.controller(element, function() { 20 | // const $ctrl = this; 21 | 22 | // $ctrl.$onInit = () => { 23 | // $ctrl.clicked = false; 24 | // }; 25 | 26 | // $ctrl.toggleClicked = () => { 27 | // $ctrl.clicked = !$ctrl.clicked; 28 | // }; 29 | // }); 30 | // triggerDoubeClick(element); 31 | // expect(element['$instance'].componentScope.$ctrl.clicked).toEqual(true); 32 | // }); 33 | 34 | // it('Must be the sum of the two numbers', () => { 35 | // const template = ` 36 | // 37 | // 38 | // 39 | // `; 40 | // const element = document.createElement('div'); 41 | // element.innerHTML = template; 42 | 43 | // capivara.controller(element, function() { 44 | // const $ctrl = this; 45 | 46 | // $ctrl.$onInit = () => { 47 | // $ctrl.numberOne = 90; 48 | // $ctrl.numberTwo = 10; 49 | // }; 50 | 51 | // $ctrl.sum = (value) => { 52 | // $ctrl.result = value; 53 | // }; 54 | // }); 55 | // triggerDoubeClick(element); 56 | // expect(element['$instance'].componentScope.$ctrl.result).toEqual(100); 57 | // }); 58 | // it('Must be the subtraction of the two numbers', () => { 59 | // const template = ` 60 | // 61 | // 62 | // 63 | // `; 64 | // const element = document.createElement('div'); 65 | // element.innerHTML = template; 66 | 67 | // capivara.controller(element, function() { 68 | // const $ctrl = this; 69 | 70 | // $ctrl.$onInit = () => { 71 | // $ctrl.numberOne = 90; 72 | // $ctrl.numberTwo = 10; 73 | // }; 74 | 75 | // $ctrl.subtract = (value) => { 76 | // $ctrl.result = value; 77 | // }; 78 | // }); 79 | // triggerDoubeClick(element); 80 | // expect(element['$instance'].componentScope.$ctrl.result).toEqual(80); 81 | // }); 82 | 83 | // it('Must be the same object', () => { 84 | // const template = ` 85 | // 86 | // `; 87 | // const element = document.createElement('div'); 88 | // element.innerHTML = template; 89 | 90 | // capivara.controller(element, function() { 91 | // const $ctrl = this; 92 | 93 | // $ctrl.$onInit = () => { 94 | // $ctrl.person = { 95 | // name: 'Mateus', 96 | // }; 97 | // }; 98 | 99 | // $ctrl.save = (person) => { 100 | // $ctrl.result = person; 101 | // }; 102 | // }); 103 | // triggerDoubeClick(element); 104 | // expect(element['$instance'].componentScope.$ctrl.result).toEqual(element['$instance'].componentScope.$ctrl.person); 105 | // }); 106 | 107 | // it('Should create the click event', (done) => { 108 | // const template = ` 109 | // 110 | // `; 111 | // const element = document.createElement('div'); 112 | // element.innerHTML = template; 113 | // capivara.controller(element, function() { 114 | // const $ctrl = this; 115 | 116 | // $ctrl.save = function() { 117 | // $ctrl.clicked = true; 118 | // }; 119 | // }); 120 | // const cpClick = new CPClick(element.querySelector('button'), null); 121 | // cpClick.create(); 122 | // triggerDoubeClick(element); 123 | // setTimeout(() => { 124 | // expect(element.querySelector('button')['$scope'].scope.$ctrl.clicked).toEqual(true); 125 | // done(); 126 | // }, 1000); 127 | // }); 128 | 129 | // }); 130 | -------------------------------------------------------------------------------- /test/spec/capivara-else-if.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test cpElseIf hide element', () => { 5 | const template = ` 6 |

Show this

7 |

Show this

8 | `; 9 | const element = document.createElement('div'); 10 | element.innerHTML = template; 11 | capivara.controller(element, function() { 12 | const $ctrl = this; 13 | $ctrl.isActive = 1; 14 | 15 | $ctrl.$onInit = () => { 16 | it("Expected h2 not found", function(done) { 17 | setTimeout(function() { 18 | expect(element.querySelector('h2')['$$cpDestroyed']).toEqual(true); 19 | done(); 20 | }); 21 | }); 22 | }; 23 | }); 24 | }); 25 | 26 | describe('test cpElseIf show element', () => { 27 | const template = ` 28 |

Show this

29 |

Show this

30 | `; 31 | const element = document.createElement('div'); 32 | element.innerHTML = template; 33 | capivara.controller(element, function() { 34 | const $ctrl = this; 35 | $ctrl.isActive = 2; 36 | 37 | $ctrl.$onInit = () => { 38 | it("Expected h2 not found", function(done) { 39 | setTimeout(function() { 40 | expect(element.querySelector('h2')['$$cpDestroyed']).toEqual(false); 41 | done(); 42 | }); 43 | }); 44 | }; 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/spec/capivara-else.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test cpElse hide element', () => { 5 | const template = ` 6 |

Show this

7 |

Not show this

8 | `; 9 | const element = document.createElement('div'); 10 | element.innerHTML = template; 11 | capivara.controller(element, function() { 12 | const $ctrl = this; 13 | $ctrl.isActive = true; 14 | 15 | $ctrl.$onInit = () => { 16 | it("Expected h2 not found", function(done) { 17 | setTimeout(function() { 18 | expect(element.querySelector('h2')['$$cpDestroyed']).toEqual(true); 19 | done(); 20 | }); 21 | }); 22 | }; 23 | }); 24 | }); 25 | 26 | describe('test cpElse show element', () => { 27 | const template = ` 28 |

Show this

29 |

Not show this

30 | `; 31 | const element = document.createElement('div'); 32 | element.innerHTML = template; 33 | document.body.appendChild(element); 34 | capivara.controller(element, function() { 35 | const $ctrl = this; 36 | $ctrl.isActive = false; 37 | 38 | $ctrl.$onViewInit = () => { 39 | it("Expected h2 found", function() { 40 | expect(element.querySelector('h2')['$$cpDestroyed']).toEqual(false); 41 | }); 42 | }; 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /test/spec/capivara-eval.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import {Eval} from '../../src/core/eval'; 3 | 4 | describe('This will be test the eval method', () => { 5 | const person = { firstName: 'Mateus', lastName: 'Miranda de Almeida', age: 22 }; 6 | it('Should return object first name', () => { 7 | expect(Eval.exec('firstName', person)).toEqual(person.firstName); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /test/spec/capivara-focus.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test of focus', () => { 5 | const template = ` 6 | 7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | const $ctrl = this; 12 | $ctrl.focused = false; 13 | 14 | $ctrl.teste = () => { 15 | $ctrl.focused = true; 16 | }; 17 | 18 | $ctrl.$onViewInit = () => { 19 | const event = new Event('focus'); 20 | element.querySelector('input').dispatchEvent(event); 21 | it('Expected attribute focused is true', (done) => { 22 | setTimeout(() => { 23 | expect($ctrl.focused).toEqual(true); 24 | done(); 25 | }); 26 | }); 27 | 28 | }; 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/spec/capivara-hide.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test of hide with fixed object', () => { 5 | const template = ` 6 |

hide this

7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | const $ctrl = this; 12 | $ctrl.isActive = false; 13 | 14 | $ctrl.$onInit = () => { 15 | it("Expected to find the element", function(done) { 16 | setTimeout(function() { 17 | expect(element.querySelector('h1').style.display).toEqual(''); 18 | done(); 19 | }); 20 | }); 21 | }; 22 | }); 23 | }); 24 | 25 | describe('test of hide with dynamic object', () => { 26 | const template = ` 27 |

hide this

28 | 55 | `; 56 | const element = document.createElement('div'); 57 | element.innerHTML = template; 58 | capivara.controller(element, function() { 59 | const $ctrl = this; 60 | $ctrl.isActive = true; 61 | $ctrl.clickMe = function() { 62 | $ctrl.isActive = !$ctrl.isActive; 63 | }; 64 | $ctrl.$onInit = () => { 65 | it("Expected h2 found and h1 not found", function(done) { 66 | setTimeout(function() { 67 | element.querySelector('button').click(); 68 | expect(element.querySelector('h1')['$$cpDestroyed']).toEqual(true); 69 | expect(element.querySelector('h2')['$$cpDestroyed']).toEqual(false); 70 | done(); 71 | setTimeout(function() { 72 | element.querySelector('button').click(); 73 | expect(element.querySelector('h1')['$$cpDestroyed']).not.toEqual(true); 74 | expect(element.querySelector('h2')['$$cpDestroyed']).not.toEqual(false); 75 | }); 76 | }); 77 | }); 78 | }; 79 | }); 80 | }); 81 | 82 | describe('test cpIf with second dynamic elements', () => { 83 | const template = ` 84 |

Show this

85 |

Not Show this

86 | 87 | `; 88 | const element = document.createElement('div'); 89 | element.innerHTML = template; 90 | capivara.controller(element, function() { 91 | const $ctrl = this; 92 | $ctrl.isActive = false; 93 | $ctrl.clickMe = function() { 94 | $ctrl.isActive = !$ctrl.isActive; 95 | }; 96 | 97 | $ctrl.$onInit = () => { 98 | it("Expected h1 found and h2 not found", function(done) { 99 | element.querySelector('button').click(); 100 | expect(element.querySelector('h1')['$$cpDestroyed']).toEqual(false); 101 | expect(element.querySelector('h2')['$$cpDestroyed']).toEqual(true); 102 | done(); 103 | setTimeout(function() { 104 | element.querySelector('button').click(); 105 | expect(element.querySelector('h1')['$$cpDestroyed']).not.toEqual(false); 106 | expect(element.querySelector('h2')['$$cpDestroyed']).not.toEqual(true); 107 | }); 108 | }); 109 | }; 110 | }); 111 | }); 112 | -------------------------------------------------------------------------------- /test/spec/capivara-init.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test of init with fixed object', () => { 5 | const template = ` 6 |

String test

7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | const $ctrl = this; 12 | $ctrl.value = ''; 13 | 14 | $ctrl.initialize = (value) => { 15 | $ctrl.value = value; 16 | }; 17 | 18 | $ctrl.$onInit = () => { 19 | it("Expected to not find the element", function(done) { 20 | setTimeout(function() { 21 | expect($ctrl.value).toEqual('This is the init function'); 22 | done(); 23 | }); 24 | }, 5000); 25 | }; 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/spec/capivara-interpolation.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test interpolation', () => { 5 | const template = ` 6 |

[[$ctrl.name]]

7 |

[[:$ctrl.name]]

8 | `; 9 | const element = document.createElement('div'); 10 | element.innerHTML = template; 11 | 12 | capivara.controller(element, function() { 13 | const $ctrl = this; 14 | 15 | $ctrl.$onInit = () => { 16 | $ctrl.name = 'Felipe'; 17 | }; 18 | 19 | $ctrl.$onViewInit = () => { 20 | setTimeout(() => { 21 | $ctrl.name = 'Felipe Sabadini'; 22 | }, 1000); 23 | it("Expected field name is equal to scope", function(done) { 24 | setTimeout(function() { 25 | expect(element.querySelector('h1').innerHTML).toEqual($ctrl.name); 26 | done(); 27 | }, 2000); 28 | }, 3000); 29 | it("Expected field name not equal to scope", function(done) { 30 | setTimeout(function() { 31 | expect(element.querySelector('h2').innerHTML).toEqual('Felipe'); 32 | done(); 33 | }, 2000); 34 | }, 3000); 35 | }; 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/spec/capivara-key.spec.ts: -------------------------------------------------------------------------------- 1 | // import { } from 'jasmine'; 2 | // import capivara from '../../src/index'; 3 | 4 | // describe('test of key', () => { 5 | // const template = ` 6 | // 7 | // `; 8 | // const element = document.createElement('div'); 9 | // element.innerHTML = template; 10 | // capivara.controller(element, function() { 11 | // const $ctrl = this; 12 | 13 | // $ctrl.$onInit = () => { 14 | // $ctrl.clicked = false; 15 | // }; 16 | 17 | // $ctrl.toggleClicked = () => { 18 | // $ctrl.clicked = !$ctrl.clicked; 19 | // }; 20 | 21 | // }); 22 | // it('The value of the variable must be true', () => { 23 | // expect(element['$instance'].componentScope.$ctrl.clicked).toEqual(true); 24 | // }); 25 | // }); 26 | -------------------------------------------------------------------------------- /test/spec/capivara-max.spec.ts: -------------------------------------------------------------------------------- 1 | // import { } from 'jasmine'; 2 | // 3 | // describe('test of max', () => { 4 | // const template = ` 5 | // 6 | // `; 7 | // const element = document.createElement('div'); 8 | // element.innerHTML = template; 9 | // 10 | // it("Expected to increase the value of the input to max", function(done) { 11 | // setTimeout(function() { element.querySelector('input').click(); }, 500); 12 | // setTimeout(function() { 13 | // expect(element.querySelector('input').value).toEqual('1'); 14 | // done(); 15 | // }, 1000); 16 | // setTimeout(function() { element.querySelector('input').click(); }, 1500); 17 | // setTimeout(function() { 18 | // expect(element.querySelector('input').value).toEqual('1'); 19 | // done(); 20 | // }, 2000); 21 | // }); 22 | // }); 23 | -------------------------------------------------------------------------------- /test/spec/capivara-maxlength.spec.ts: -------------------------------------------------------------------------------- 1 | // import {} from 'jasmine'; 2 | // import capivara from '../../src/index'; 3 | 4 | // describe('Directive cp-maxlength', () => { 5 | 6 | // it("Expected field maxLength are equal to 10", function(done) { 7 | // const template = ` 8 | // 9 | // `; 10 | // const element = document.createElement('div'); 11 | // element.innerHTML = template; 12 | // capivara.controller(element, function() { 13 | // const $ctrl = this; 14 | // $ctrl.$onViewInit = () => { 15 | // setTimeout(function() { 16 | // expect(element.querySelector('input').maxLength).toEqual(10); 17 | // done(); 18 | // }, 0); 19 | // }; 20 | // }); 21 | // }); 22 | 23 | // it("Expected field maxLength are equal to the local variable", function(done) { 24 | // const template = ` 25 | // 26 | // `; 27 | // const element = document.createElement('div'); 28 | // element.innerHTML = template; 29 | // capivara.controller(element, function() { 30 | // const $ctrl = this; 31 | // $ctrl.max = 20; 32 | // $ctrl.$onViewInit = () => { 33 | // setTimeout(function() { 34 | // expect(element.querySelector('input').maxLength).toEqual($ctrl.max); 35 | // done(); 36 | // }, 0); 37 | // }; 38 | // }); 39 | // }); 40 | // }); 41 | -------------------------------------------------------------------------------- /test/spec/capivara-min.spec.ts: -------------------------------------------------------------------------------- 1 | // import { } from 'jasmine'; 2 | // 3 | // describe('test of min', () => { 4 | // const template = ` 5 | // 6 | // `; 7 | // const element = document.createElement('div'); 8 | // element.innerHTML = template; 9 | // 10 | // it("Expected to decrease the input value to zero", function(done) { 11 | // setTimeout(function() { element.querySelector('input').click(); }, 500); 12 | // setTimeout(function() { 13 | // expect(element.querySelector('input').value).toEqual('0'); 14 | // done(); 15 | // }, 1000); 16 | // setTimeout(function() { element.querySelector('input').click(); }, 1500); 17 | // setTimeout(function() { 18 | // expect(element.querySelector('input').value).toEqual('0'); 19 | // done(); 20 | // }, 2000); 21 | // }); 22 | // }); 23 | -------------------------------------------------------------------------------- /test/spec/capivara-model.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test model scope to field', () => { 5 | const template = ` 6 | 7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | const $ctrl = this; 12 | $ctrl.$onInit = () => { 13 | $ctrl.name = 'Mateus Miranda'; 14 | 15 | it("Expected field value is equal to scope", function(done) { 16 | setTimeout(function() { 17 | expect(element.querySelector('input').value).toEqual($ctrl.name); 18 | done(); 19 | }); 20 | }); 21 | 22 | }; 23 | }); 24 | }); 25 | 26 | describe('test model field to scope', () => { 27 | const template = ` 28 | 29 | `; 30 | const element = document.createElement('div'); 31 | element.innerHTML = template; 32 | capivara.controller(element, function() { 33 | const $ctrl = this; 34 | $ctrl.$onViewInit = () => { 35 | element.querySelector('input').setAttribute('value', 'Mateus Miranda'); 36 | Object.keys(element['$scope'].mapDom.directives.cpModelsElements).forEach((key) => { 37 | element['$scope'].mapDom.directives.cpModelsElements[key].forEach((elm) => elm.applyValueInModel()); 38 | }); 39 | it("Expected field value is equal to scope", function(done) { 40 | setTimeout(function() { 41 | expect(element.querySelector('input').value).toEqual($ctrl.name); 42 | done(); 43 | }); 44 | }); 45 | }; 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/spec/capivara-mouse.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test of mousein and out', () => { 5 | const template = ` 6 | 7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | const $ctrl = this; 12 | $ctrl.mousein = function() { 13 | $ctrl.test = 'mousein'; 14 | }; 15 | 16 | $ctrl.mouseout = function() { 17 | $ctrl.test = 'mouseout'; 18 | }; 19 | 20 | $ctrl.$onViewInit = () => { 21 | const evtIn = new Event('mouseover'); 22 | const evtOut = new Event('mouseout'); 23 | element.querySelector('input').dispatchEvent(evtIn); 24 | element.querySelector('input').dispatchEvent(evtOut); 25 | 26 | it('expect the element test have value mouseout', (done) => { 27 | expect(element.querySelector('input').value).toEqual('mouseout'); 28 | done(); 29 | }); 30 | }; 31 | 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/spec/capivara-no-bind.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test no bind', () => { 5 | const template = ` 6 | 7 |
8 |

[[4+4]]

9 |
10 | `; 11 | const element = document.createElement('div'); 12 | element.innerHTML = template; 13 | capivara.controller(element, function() { 14 | 15 | it("Expected ignore interpolation", function(done) { 16 | setTimeout(function() { 17 | expect(element.querySelector('div h1').innerHTML).toEqual('[[4+4]]'); 18 | done(); 19 | }); 20 | }); 21 | 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/spec/capivara-placeholder.spec.ts: -------------------------------------------------------------------------------- 1 | import {} from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('Directive cp-attr.placeholder', () => { 5 | it("", () => { 6 | const template = ` 7 | 8 | 9 | `; 10 | const element = document.createElement('div'); 11 | element.innerHTML = template; 12 | capivara.controller(element, function() { 13 | this.name = 'Test'; 14 | 15 | this.test = () => { 16 | this.name = 'Testing'; 17 | }; 18 | 19 | this.$onViewInit = () => { 20 | const event = new Event('click'); 21 | element.querySelector('button').dispatchEvent(event); 22 | setTimeout(() => { 23 | expect(element.querySelector('input').getAttribute('placeholder')).toEqual('Testing'); 24 | }); 25 | }; 26 | }); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/spec/capivara-polyfill.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import { Polyfill } from '../../src/core/observer/polyfill'; 3 | 4 | describe('test of polyfill methods', () => { 5 | const person = { 6 | name: 'John', 7 | lastName: 'Smith', 8 | }; 9 | Polyfill.unWatchProperty(person, 'job'); 10 | const keys = Object.keys(person); 11 | it('should unWatchProperty of a object ', function() { 12 | expect(keys.length).toEqual(3); 13 | }); 14 | }); 15 | 16 | // describe('test of polyfill methods', () => { 17 | // const person = { 18 | // name: 'John', 19 | // lastName: 'Smith', 20 | // }; 21 | // 22 | // const someFunc = function() { 23 | // }; 24 | // 25 | // Polyfill.setDirtyCheck(person, 1, ''); 26 | // it('should setDirtyCheck of a object ', function() { 27 | // expect(person['__observer__']).toEqual(2); 28 | // }); 29 | // }); 30 | 31 | describe('test of polyfill methods', () => { 32 | const person = { 33 | name: 'John', 34 | lastName: 'Smith', 35 | }; 36 | 37 | Polyfill.clearDirtyCheck(person); 38 | it('should setDirtyCheck of a object ', function() { 39 | expect(person['__observer__']).toEqual(undefined); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/spec/capivara-repeat.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test of repeat with fixed object', () => { 5 | const template = ` 6 |

[[person.name]]

7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | const $ctrl = this; 12 | $ctrl.persons = [ 13 | { name: 'John' }, 14 | { name: 'Bob' }, 15 | { name: 'Anna' }, 16 | { name: 'Kyle' }, 17 | ]; 18 | 19 | $ctrl.$onInit = () => { 20 | it("Expected find 4 children", function(done) { 21 | setTimeout(function() { 22 | expect(element.childElementCount).toEqual($ctrl.persons.length); 23 | done(); 24 | }); 25 | }, 5000); 26 | }; 27 | }); 28 | }); 29 | 30 | describe('test of repeat with dynamic object', () => { 31 | const template = ` 32 |

[[person.name]]

33 | 34 | `; 35 | const element = document.createElement('div'); 36 | element.innerHTML = template; 37 | capivara.controller(element, function() { 38 | const $ctrl = this; 39 | 40 | $ctrl.persons = [ 41 | { name: 'John' }, 42 | { name: 'Bob' }, 43 | { name: 'Anna' }, 44 | { name: 'Kyle' }, 45 | ]; 46 | 47 | $ctrl.add = function() { 48 | $ctrl.persons.push({ name: 'Carlos' }); 49 | }; 50 | 51 | $ctrl.$onViewInit = () => { 52 | element.querySelector('button').click(); 53 | it("Expected find 5 children", function(done) { 54 | setTimeout(function() { 55 | expect(element.querySelectorAll('h1').length).toEqual($ctrl.persons.length); 56 | done(); 57 | }); 58 | }, 7000); 59 | }; 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /test/spec/capivara-show.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test of show with fixed object', () => { 5 | const template = ` 6 |

Show this

7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | const $ctrl = this; 12 | $ctrl.isActive = false; 13 | 14 | $ctrl.$onInit = () => { 15 | it("Expected to not find the element", function(done) { 16 | setTimeout(function() { 17 | expect(element.querySelector('h1').style.display).toEqual('none'); 18 | done(); 19 | }); 20 | }, 10000); 21 | }; 22 | }); 23 | }); 24 | 25 | describe('test of show with dynamic object', () => { 26 | const template = ` 27 |

Show this

28 | `; 29 | const element = document.createElement('div'); 30 | element.innerHTML = template; 31 | capivara.controller(element, function() { 32 | const $ctrl = this; 33 | $ctrl.isActive = true; 34 | 35 | $ctrl.$onInit = () => { 36 | it("Expected to not find the element", function(done) { 37 | setTimeout(function() { 38 | expect(element.querySelector('h1').style.display).toEqual(''); 39 | done(); 40 | }); 41 | }, 10000); 42 | }; 43 | 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/spec/capivara-src.spec.ts: -------------------------------------------------------------------------------- 1 | // import {} from 'jasmine'; 2 | // import capivara from '../../src/index'; 3 | 4 | // describe('Directive cp-attr.src', () => { 5 | 6 | // it("Should set the src dynamically", function(done) { 7 | 8 | // const template = ` 9 | // 10 | // `; 11 | // const element = document.createElement('div'); 12 | // element.innerHTML = template; 13 | // capivara.controller(element, function() { 14 | // const $ctrl = this; 15 | // $ctrl.src = 'https://avatars1.githubusercontent.com/u/33517395?s=200&v=4'; 16 | 17 | // $ctrl.$onInit = () => { 18 | // setTimeout(function() { 19 | // expect(element.querySelector('img').src).toEqual($ctrl.src); 20 | // done(); 21 | // }, 2000); 22 | // }; 23 | // }); 24 | // }); 25 | 26 | // it("Should set the src dynamically", function(done) { 27 | 28 | // const template = ` 29 | // 30 | // 31 | // `; 32 | // const element = document.createElement('div'); 33 | // element.innerHTML = template; 34 | // capivara.controller(element, function() { 35 | // const $ctrl = this; 36 | // $ctrl.src = 'https://avatars1.githubusercontent.com/u/33517395?s=200&v=4'; 37 | 38 | // $ctrl.click = () => { 39 | // $ctrl.src = 'https://bit.ly/2pTjZnU'; 40 | // }; 41 | 42 | // $ctrl.$onInit = () => { 43 | // setTimeout(function() { 44 | // element.querySelector('button').click(); 45 | // }, 1000); 46 | // setTimeout(function() { 47 | // expect(element.querySelector('img').src).toEqual('https://bit.ly/2pTjZnU'); 48 | // done(); 49 | // }, 2000); 50 | // }; 51 | // }); 52 | // }); 53 | // }); 54 | -------------------------------------------------------------------------------- /test/spec/capivara-step.spec.ts: -------------------------------------------------------------------------------- 1 | // import { } from 'jasmine'; 2 | // 3 | // describe('test of step', () => { 4 | // const template = ` 5 | // 6 | // `; 7 | // const element = document.createElement('div'); 8 | // element.innerHTML = template; 9 | // 10 | // it("Expected to add the step size on the input value", function(done) { 11 | // setTimeout(function() { element.querySelector('input').click(); }, 500); 12 | // setTimeout(function() { 13 | // expect(element.querySelector('input').value).toEqual('3'); 14 | // done(); 15 | // }, 1000); 16 | // setTimeout(function() { element.querySelector('input').click(); }, 1500); 17 | // setTimeout(function() { 18 | // expect(element.querySelector('input').value).toEqual('6'); 19 | // done(); 20 | // }, 2000); 21 | // }); 22 | // }); 23 | -------------------------------------------------------------------------------- /test/spec/capivara-style.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('test of style with fixed object', () => { 5 | const template = ` 6 |

Sample HTML text

7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | const $ctrl = this; 12 | $ctrl.activeStyle = 'red'; 13 | 14 | $ctrl.$onInit = () => { 15 | it('Expected to add the style', () => { 16 | expect(element.querySelector('h1').style.background).toEqual('red'); 17 | }); 18 | }; 19 | }); 20 | }); 21 | 22 | describe('test of style with dynamic object', () => { 23 | const template = ` 24 |

String of test

25 | `; 26 | const element = document.createElement('div'); 27 | element.innerHTML = template; 28 | capivara.controller(element, function() { 29 | const $ctrl = this; 30 | $ctrl.backGround = 'red'; 31 | $ctrl.fontColor = 'blue'; 32 | $ctrl.sizeFont = '20px'; 33 | 34 | $ctrl.getStyle = () => { 35 | return { 36 | ['background-color']: $ctrl.backGround, 37 | [' color: ']: $ctrl.fontColor, 38 | ['font-size']: $ctrl.sizeFont, 39 | }; 40 | }; 41 | 42 | $ctrl.$onInit = () => { 43 | it("Expected to add the style", function(done) { 44 | setTimeout(function() { 45 | expect(element.querySelector('h1').style.backgroundColor).toEqual('red'); 46 | done(); 47 | }); 48 | }); 49 | }; 50 | }); 51 | }); 52 | 53 | describe('test of style with dynamic object', () => { 54 | const template = ` 55 |

Sample HTML text

56 | 57 | `; 58 | const element = document.createElement('div'); 59 | element.innerHTML = template; 60 | capivara.controller(element, function() { 61 | const $ctrl = this; 62 | $ctrl.color = 'blue'; 63 | 64 | $ctrl.click = () => { 65 | $ctrl.color = 'red'; 66 | }; 67 | 68 | $ctrl.$onInit = () => { 69 | it("Expected to add the style", function(done) { 70 | setTimeout(function() { element.querySelector('button').click(); }, 1000); 71 | setTimeout(function() { 72 | expect(element.querySelector('h1').style.background).toEqual('red'); 73 | done(); 74 | }, 2000); 75 | }); 76 | }; 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /test/spec/capivara-title.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import capivara from '../../src/index'; 3 | 4 | describe('Directive cp-attr.tittle', () => { 5 | const template = ` 6 |

test

7 | `; 8 | const element = document.createElement('div'); 9 | element.innerHTML = template; 10 | capivara.controller(element, function() { 11 | this.var = 'test1'; 12 | 13 | this.$onViewInit = () => { 14 | it('expect the element title = test1 be found', (done) => { 15 | expect(element.querySelector('h1').getAttribute("title")).toEqual('test1'); 16 | done(); 17 | }); 18 | }; 19 | 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /test/spec/capivara-util.spec.ts: -------------------------------------------------------------------------------- 1 | import { } from 'jasmine'; 2 | import { Util } from '../../src/core/observer/util'; 3 | 4 | describe('Tests of the util methods', () => { 5 | const a = [1, 2, 3, 4, 5, 6, 7]; 6 | const b = [1, 2, 3, 9]; 7 | 8 | const result = Util.diff(a, b); 9 | it('should return added elements', function() { 10 | expect(result.added).toEqual(['9']); 11 | }); 12 | 13 | it('should return deleted elements', function() { 14 | expect(result.deleted).toEqual(['4', '5', '6', '7']); 15 | }); 16 | 17 | it('should return all the common elements on the array', function() { 18 | expect(result.all).toEqual(['4', '5', '6', '7', '9']); 19 | }); 20 | }); 21 | 22 | describe('Tests of the util methods', () => { 23 | const a = ['1', '2', '3', '4', '5', '6', '7']; 24 | const b = ['1', '2', '3', '9']; 25 | 26 | const firstResult = Util.compare(a, b); 27 | it('should return the comparison are false', function() { 28 | expect(firstResult).toEqual(false); 29 | }); 30 | 31 | const c = ['1', '2', '3', '4', '5', '6', '7']; 32 | const d = ['1', '3', '2', '4', '5', '6', '7']; 33 | 34 | const secondResult = Util.compare(c, d); 35 | it('should return the comparison are false', function() { 36 | expect(secondResult).toEqual(false); 37 | }); 38 | 39 | const thirdResult = Util.compare(c, a); 40 | it('should return the comparison are true', function() { 41 | expect(thirdResult).toEqual(true); 42 | }); 43 | 44 | }); 45 | 46 | describe('Tests of the util methods', () => { 47 | const person = { 48 | name: 'John', 49 | lastName: 'Smith', 50 | }; 51 | const getKeys = Util.keys(person); 52 | 53 | it('should return the keys of the object', function() { 54 | expect(getKeys).toEqual(["name", "lastName"]); 55 | }); 56 | }); 57 | 58 | describe('Tests of the util methods', () => { 59 | const person = { 60 | name: 'John', 61 | lastName: 'Smith', 62 | }; 63 | const otherPerson = Util.clone(person); 64 | it('should return true if the objects are equal', function() { 65 | expect(Util.keys(otherPerson)).toEqual(Util.keys(person)); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "allowSyntheticDefaultImports": true, 5 | "declaration": false, 6 | "types": ["node"], 7 | "emitDecoratorMetadata": true, 8 | "experimentalDecorators": true, 9 | "lib": [ 10 | "dom", 11 | "es2015" 12 | ], 13 | "module": "es2015", 14 | "moduleResolution": "node", 15 | "target": "es5" 16 | }, 17 | "include": [ 18 | "src/**/*.ts" 19 | ], 20 | "globals": { 21 | "require": true 22 | }, 23 | "exclude": [ 24 | "node_modules" 25 | ], 26 | "compileOnSave": false, 27 | "atom": { 28 | "rewriteTsconfig": false 29 | } 30 | } -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "only-arrow-functions": false, 9 | "no-var-requires": false, 10 | "no-string-literal": false, 11 | "no-console": false, 12 | "object-literal-sort-keys": false, 13 | "max-line-length": [false], 14 | "quotemark": ["single"], 15 | "variable-name": ["allow-leading-underscore"], 16 | "no-empty": false, 17 | "jsdoc-format": false, 18 | "member-ordering": false, 19 | "interface-name": [true, "never-prefix"], 20 | "no-namespace": false, 21 | "no-eval": false, 22 | "one-variable-per-declaration": false, 23 | "no-conditional-assignment": false, 24 | "no-unused-expression": [false] 25 | }, 26 | "rulesDirectory": [] 27 | } 28 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015-rollup"] 3 | } 4 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | yarn-error.log 4 | test/reports 5 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 wi2 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## webpack-nightwatch-plugin 3 | 4 | 5 | #### NightWatch config 6 | ``` 7 | //test/nightwatch.conf.js 8 | 9 | var selenium = require('selenium-server-standalone-jar'); 10 | var chromedriver = require('chromedriver'); 11 | 12 | module.exports = { 13 | src_folders: ['./test/ui'], 14 | output_folder: './test/reports', 15 | selenium: { 16 | start_process: true, 17 | server_path: selenium.path, 18 | log_path: './test/reports', 19 | cli_args: { 20 | 'webdriver.chrome.driver': chromedriver.path, 21 | 'webdriver.ie.driver': '' 22 | } 23 | }, 24 | test_settings: { 25 | default: { 26 | launch_url: 'http://localhost:8080/', 27 | selenium_port: 4444, 28 | selenium_host: 'localhost', 29 | desiredCapabilities: { 30 | browserName: 'chrome', 31 | javascriptEnabled: true, 32 | acceptSslCerts: true 33 | }, 34 | } 35 | }, 36 | "chrome" : { 37 | "desiredCapabilities" : { 38 | "browserName" : "chrome", 39 | "chromeOptions" : { 40 | "args" : [ 41 | "use-fake-device-for-media-stream", 42 | "use-fake-ui-for-media-stream" 43 | ] 44 | } 45 | } 46 | } 47 | }; 48 | ``` 49 | 50 | #### Webpack config 51 | ``` 52 | //webpack.config.js 53 | 54 | config.plugins.push( 55 | new WebpackNightWatchPlugin({ 56 | url: './test/nightwatch.conf.js' 57 | }) 58 | ) 59 | ``` 60 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/index.js: -------------------------------------------------------------------------------- 1 | import path from 'path' 2 | import {spawn, spawnSync} from 'child_process' 3 | 4 | export default class WebpackNightWatchPlugin { 5 | 6 | constructor(options = {}) { 7 | const defaultOptions = { 8 | onEmit: false 9 | } 10 | this.options = Object.assign({}, defaultOptions, options) 11 | } 12 | 13 | apply(compiler) { 14 | 15 | compiler.plugin('compilation', (compilation) => { 16 | spawnSync('pkill', ['-f', 'selenium']) 17 | }) 18 | 19 | compiler.plugin(this.options.onEmit ? 'emit' : 'done', (compilation, callback) => { 20 | const env = Object.assign({}, process.env, {LANG: 'en_US.UTF-8'}); 21 | console.log(__dirname) 22 | const nightwatch = spawn(path.join(__dirname, '../node_modules/.bin/nightwatch'), [ 23 | '-c', 24 | this.options.url 25 | ], {env}) 26 | 27 | nightwatch.stdout.on('data', data => { 28 | process.stdout.write(data.toString()) 29 | }) 30 | 31 | nightwatch.stderr.on('data', data => { 32 | process.stdout.write(data.toString()) 33 | }) 34 | 35 | nightwatch.on('close', () => { 36 | if (this.options.onEmit) callback() 37 | spawnSync('pkill', ['-f', 'selenium']) 38 | }) 39 | }) 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "_from": "webpack-nightwatch-plugin", 3 | "_id": "webpack-nightwatch-plugin@1.0.0", 4 | "_inBundle": false, 5 | "_integrity": "sha1-xatQte+SyDHi406R1TZhf2tra40=", 6 | "_location": "/webpack-nightwatch-plugin", 7 | "_phantomChildren": {}, 8 | "_requested": { 9 | "type": "tag", 10 | "registry": true, 11 | "raw": "webpack-nightwatch-plugin", 12 | "name": "webpack-nightwatch-plugin", 13 | "escapedName": "webpack-nightwatch-plugin", 14 | "rawSpec": "", 15 | "saveSpec": null, 16 | "fetchSpec": "latest" 17 | }, 18 | "_requiredBy": [ 19 | "#DEV:/", 20 | "#USER" 21 | ], 22 | "_resolved": "https://registry.npmjs.org/webpack-nightwatch-plugin/-/webpack-nightwatch-plugin-1.0.0.tgz", 23 | "_shasum": "c5ab50b5ef92c831e2e34e91d536617f6b6b6b8d", 24 | "_spec": "webpack-nightwatch-plugin", 25 | "_where": "/home/mateus/capivara/capivarajs", 26 | "author": { 27 | "name": "Mike wi2" 28 | }, 29 | "bugs": { 30 | "url": "https://github.com/wi2/webpack-nightwatch-plugin/issues" 31 | }, 32 | "bundleDependencies": false, 33 | "dependencies": { 34 | "child_process": "^1.0.2", 35 | "nightwatch": "^0.9.8" 36 | }, 37 | "deprecated": false, 38 | "description": "Webpack plugin, Browser Automation with Nightwatch.js", 39 | "devDependencies": { 40 | "ava": "^0.16.0", 41 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 42 | "babel-plugin-transform-runtime": "^6.15.0", 43 | "babel-preset-es2015": "^6.18.0", 44 | "babel-preset-es2015-rollup": "^1.2.0", 45 | "chromedriver": "^2.24.1", 46 | "rollup-plugin-babel": "^2.6.1", 47 | "rollup-plugin-json": "^2.0.2", 48 | "selenium-server-standalone-jar": "^3.0.1", 49 | "webpack": "^1.13.3" 50 | }, 51 | "homepage": "https://github.com/wi2/webpack-nightwatch-plugin#readme", 52 | "keywords": [ 53 | "webpack", 54 | "plugin", 55 | "Nightwatch" 56 | ], 57 | "license": "MIT", 58 | "main": "lib/index.js", 59 | "name": "webpack-nightwatch-plugin", 60 | "repository": { 61 | "type": "git", 62 | "url": "git+ssh://git@github.com/wi2/webpack-nightwatch-plugin.git" 63 | }, 64 | "scripts": { 65 | "build": "rollup -c", 66 | "test": "npm run build && ava -v test/*.spec.js" 67 | }, 68 | "version": "1.0.0" 69 | } 70 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/rollup.config.js: -------------------------------------------------------------------------------- 1 | import babel from 'rollup-plugin-babel'; 2 | 3 | export default { 4 | entry: 'index.js', 5 | format: 'cjs', 6 | plugins: [ 7 | babel() 8 | ], 9 | dest: 'lib/index.js' 10 | }; 11 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/test/index.spec.js: -------------------------------------------------------------------------------- 1 | import test from 'ava' 2 | import webpack from 'webpack' 3 | import WebpackNightWatchPlugin from '../lib/index' 4 | 5 | const webpackConfig = { 6 | plugins: [ 7 | new WebpackNightWatchPlugin({ 8 | onEmit: true, 9 | url: './nightwatch.conf.js' 10 | }) 11 | ] 12 | } 13 | 14 | test('webpack', async t => { 15 | const promise = new Promise((resolve, reject) => { 16 | webpack(webpackConfig, (err, stats) => { 17 | if (err || stats.hasErrors()) { 18 | reject(err) 19 | } 20 | resolve(typeof stats) 21 | }) 22 | }) 23 | t.is(await promise, 'object') 24 | }) 25 | 26 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/test/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | var selenium = require('selenium-server-standalone-jar'); 2 | var chromedriver = require('chromedriver'); 3 | 4 | module.exports = { 5 | src_folders: ['ui'], 6 | output_folder: 'reports', 7 | selenium: { 8 | start_process: true, 9 | server_path: selenium.path, 10 | log_path: 'reports', 11 | cli_args: { 12 | 'webdriver.chrome.driver': chromedriver.path, 13 | 'webdriver.ie.driver': '' 14 | } 15 | }, 16 | test_settings: { 17 | default: { 18 | launch_url: 'https://google.fr/', 19 | selenium_port: 4444, 20 | selenium_host: 'localhost', 21 | desiredCapabilities: { 22 | browserName: 'chrome', 23 | javascriptEnabled: true, 24 | acceptSslCerts: true 25 | }, 26 | } 27 | }, 28 | "chrome" : { 29 | "desiredCapabilities" : { 30 | "browserName" : "chrome", 31 | "chromeOptions" : { 32 | "args" : [ 33 | "use-fake-device-for-media-stream", 34 | "use-fake-ui-for-media-stream" 35 | ] 36 | } 37 | } 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /webpack-nightwatch-plugin/test/ui/ui.nightwatch.js: -------------------------------------------------------------------------------- 1 | const timer = 2500 2 | const wait = 1000 3 | 4 | module.exports = { 5 | after: browser => { 6 | console.log('Closing down...') 7 | browser.end() 8 | }, 9 | 10 | 'should be able to init a session': browser => { 11 | browser 12 | .url(browser.launch_url) 13 | .waitForElementVisible('body', timer); 14 | }, 15 | 16 | 'should be able to see body': browser => { 17 | browser.assert.elementPresent('body'); 18 | }, 19 | 20 | 'should be equal to https://www.google.fr/': browser => { 21 | browser.assert.urlEquals('https://www.google.fr/'); 22 | }, 23 | } 24 | --------------------------------------------------------------------------------