├── .auditignore ├── .editorconfig ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── custom.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .istanbul.yml ├── .prettierrc ├── .publishrc ├── .vscode └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── definitions └── pixi.d.ts ├── deploy-example.sh ├── example ├── Game.ts ├── config │ └── MyConfig.ts ├── index.ts ├── mediator │ ├── RobotlegsMediator.ts │ └── SmileyMediator.ts ├── tsconfig.json └── view │ ├── RobotlegsView.ts │ └── SmileyView.ts ├── karma.conf.js ├── package.json ├── src ├── index.ts └── robotlegs │ └── bender │ ├── bundles │ └── pixi │ │ └── PixiBundle.ts │ └── extensions │ ├── contextView │ ├── ContextViewExtension.ts │ ├── api │ │ └── IContextView.ts │ ├── impl │ │ ├── ContextView.ts │ │ └── ContextViewListenerConfig.ts │ └── pixiPatch │ │ ├── contains-patch.ts │ │ ├── eventemitter3-patch.ts │ │ └── pixi-patch.ts │ ├── mediatorMap │ ├── MediatorMapExtension.ts │ ├── api │ │ ├── IMediator.ts │ │ ├── IMediatorMap.ts │ │ └── IMediatorMapping.ts │ ├── dsl │ │ ├── IMediatorConfigurator.ts │ │ ├── IMediatorMapper.ts │ │ └── IMediatorUnmapper.ts │ └── impl │ │ ├── Mediator.ts │ │ ├── MediatorFactory.ts │ │ ├── MediatorManager.ts │ │ ├── MediatorMap.ts │ │ ├── MediatorMapper.ts │ │ ├── MediatorMapping.ts │ │ ├── MediatorViewHandler.ts │ │ └── NullMediatorUnmapper.ts │ └── viewManager │ ├── ManualStageObserverExtension.ts │ ├── StageCrawlerExtension.ts │ ├── StageObserverExtension.ts │ ├── ViewManagerExtension.ts │ ├── api │ ├── IViewHandler.ts │ └── IViewManager.ts │ └── impl │ ├── ConfigureViewEvent.ts │ ├── ContainerBinding.ts │ ├── ContainerBindingEvent.ts │ ├── ContainerRegistry.ts │ ├── ContainerRegistryEvent.ts │ ├── ManualStageObserver.ts │ ├── StageCrawler.ts │ ├── StageObserver.ts │ ├── ViewManager.ts │ └── ViewManagerEvent.ts ├── static ├── images │ ├── loading.gif │ ├── pixijs-v5-logo.png │ └── robotlegs.png ├── index.html ├── manifest.json ├── scripts │ └── cache-polyfill.js ├── service-worker.js └── styles │ ├── example.css │ └── main.css ├── test ├── README.md ├── entry.ts ├── index.ts ├── robotlegs │ └── bender │ │ ├── bundles │ │ └── pixi │ │ │ └── pixiBundle.test.ts │ │ └── extensions │ │ ├── contextView │ │ ├── contextViewExtension.test.ts │ │ ├── impl │ │ │ ├── contextView.test.ts │ │ │ └── contextViewListenerConfig.test.ts │ │ ├── pixiPatch │ │ │ ├── containsPatch.test.ts │ │ │ ├── eventemitter3Patch.test.ts │ │ │ └── pixiPatch.test.ts │ │ └── support │ │ │ ├── CallbackLogTarget.ts │ │ │ └── LogParams.ts │ │ ├── mediatorMap │ │ ├── impl │ │ │ ├── mediatorFactory.test.ts │ │ │ ├── mediatorManager.test.ts │ │ │ ├── mediatorMap.test.ts │ │ │ ├── mediatorMapPreload.test.ts │ │ │ ├── mediatorMapper.test.ts │ │ │ └── mediatorViewHandler.test.ts │ │ ├── mediatorMapExtension.test.ts │ │ └── support │ │ │ ├── Alpha50PercentHook.ts │ │ │ ├── CallbackHook.ts │ │ │ ├── CallbackMediator.ts │ │ │ ├── EmptyMediator.ts │ │ │ ├── ExampleDisplayObjectMediator.ts │ │ │ ├── ExampleMediator.ts │ │ │ ├── ExampleMediator2.ts │ │ │ ├── GrumpyGuard.ts │ │ │ ├── HappyGuard.ts │ │ │ ├── HookWithMediatorAndViewInjectionReportFunction.ts │ │ │ ├── InjectedMediator.ts │ │ │ ├── LifecycleReportingMediator.ts │ │ │ ├── MediatorHook.ts │ │ │ ├── MediatorWatcher.ts │ │ │ ├── NotAView.ts │ │ │ ├── NotAViewMediator.ts │ │ │ ├── NullMediator.ts │ │ │ ├── NullMediator2.ts │ │ │ ├── OnlyIfViewHasChildrenGuard.ts │ │ │ ├── RectangleMediator.ts │ │ │ ├── ViewInjectedAsRequestedMediator.ts │ │ │ └── ViewInjectedMediator.ts │ │ └── viewManager │ │ ├── impl │ │ ├── configureViewEvent.test.ts │ │ ├── containerBinding.test.ts │ │ ├── containerBindingEvent.test.ts │ │ ├── containerRegistry.test.ts │ │ ├── containerRegistryEvent.test.ts │ │ ├── manualStageObserver.test.ts │ │ ├── stageCrawler.test.ts │ │ ├── stageObserver.test.ts │ │ ├── viewManager.test.ts │ │ └── viewManagerEvent.test.ts │ │ ├── manualStageObserverExtension.test.ts │ │ ├── stageCrawlerExtension.test.ts │ │ ├── stageObserverExtension.test.ts │ │ ├── support │ │ ├── CallbackViewHandler.ts │ │ └── TreeContainer.ts │ │ └── viewManagerExtension.test.ts └── tsconfig.json ├── tsconfig.example.json ├── tsconfig.json ├── tsconfig.test.json ├── tslint.example.json ├── tslint.json ├── tslint.test.json ├── webpack.config.js ├── webpack.example.config.js └── yarn.lock /.auditignore: -------------------------------------------------------------------------------- 1 | https://npmjs.com/advisories/12 2 | https://npmjs.com/advisories/577 3 | https://npmjs.com/advisories/663 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | indent_style = space 8 | indent_size = 4 9 | 10 | [*.{ts}] 11 | indent_style = space 12 | indent_size = 4 13 | 14 | [*.{js,json}] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [{.auditignore,.codeclimate.yml,.eslintignore,.eslintrc,.istanbul.yml,.prettierrc,.publishrc,.travis.yml}] 19 | indent_style = space 20 | indent_size = 2 21 | -------------------------------------------------------------------------------- /.github/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 contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at contact@robotlegsjs.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to RobotlegsJS-Pixi 2 | 3 | ## Setup 4 | 5 | 1 - Clone your fork of the repository: 6 | ``` 7 | $ git clone https://github.com/YOUR_USERNAME/RobotlegsJS-Pixi.git 8 | ``` 9 | 10 | 2 - Install npm dependencies using yarn: 11 | ``` 12 | $ yarn install 13 | ``` 14 | 15 | 3 - Run start process 16 | ``` 17 | $ yarn start 18 | ``` 19 | 20 | 4 - Run test process 21 | ``` 22 | $ yarn test 23 | ``` 24 | 25 | ## Guidelines 26 | 27 | - Please try to [combine multiple commits before 28 | pushing](http://stackoverflow.com/questions/6934752/combining-multiple-commits-before-pushing-in-git). 29 | 30 | - Please use `TDD` when fixing bugs. This means that you should write a unit 31 | test that fails because it reproduces the issue, then fix the issue and finally run 32 | the test to ensure that the issue has been resolved. This helps us to prevent 33 | fixed bugs from happening again in the future. 34 | 35 | - Always format your code using `yarn run autoformat`. 36 | 37 | - Please keep the test coverage at 100%. Write additional unit test if 38 | necessary. 39 | 40 | - Please create an issue before sending a PR if your commit is going to change the 41 | public interface of the package or it includes significant architecture 42 | changes. 43 | 44 | - Feel free to ask for help from other members of the RobotlegsJS team via the 45 | [gitter chat](https://gitter.im/RobotlegsJS/RobotlegsJS) or 46 | [github issues](https://github.com/RobotlegsJS/RobotlegsJS-Pixi/issues). -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | tidelift: "npm/@robotlegsjs/pixi" -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/custom.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Custom issue template 3 | about: Open a general issue request 4 | 5 | --- 6 | 7 | 8 | 9 | ## Expected Behavior 10 | 11 | 12 | 13 | ## Current Behavior 14 | 15 | 16 | 17 | ## Possible Solution 18 | 19 | 20 | 21 | ## Steps to Reproduce (for bugs) 22 | 23 | 24 | 1. 25 | 2. 26 | 3. 27 | 4. 28 | 29 | ## Context 30 | 31 | 32 | 33 | ## Your Environment 34 | 35 | * Version used: 36 | * Environment name and version (e.g. Chrome 39, node.js 5.4): 37 | * Operating System and version (desktop or mobile): 38 | * Link to your project: 39 | 40 | # Stack trace 41 | 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Description 4 | 5 | 6 | 7 | ## Related Issue 8 | 9 | 10 | 11 | 12 | 13 | 14 | ## Motivation and Context 15 | 16 | 17 | 18 | ## How Has This Been Tested? 19 | 20 | 21 | 22 | 23 | 24 | ## Types of changes 25 | 26 | 27 | 28 | - [ ] Updated docs / Refactor code / Added a tests case (non-breaking change) 29 | - [ ] Bug fix (non-breaking change which fixes an issue) 30 | - [ ] New feature (non-breaking change which adds functionality) 31 | - [ ] Breaking change (fix or feature that would cause existing functionality to change) 32 | 33 | ## Checklist: 34 | 35 | 36 | 37 | 38 | - [ ] My code follows the code style of this project. 39 | - [ ] My change requires a change to the documentation. 40 | - [ ] I have updated the documentation accordingly. 41 | - [ ] I have read the **CONTRIBUTING** document. 42 | - [ ] I have added tests to cover my changes. 43 | - [ ] All new and existing tests passed. 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .nyc_output 3 | coverage 4 | dist 5 | dist/lib 6 | dist-test 7 | gh-pages 8 | lib 9 | lib-example 10 | lib-test 11 | node_modules 12 | *.as 13 | *.iml 14 | src/**/*.js 15 | src/**/*.js.map 16 | test/**/*.js 17 | test/**/*.js.map 18 | npm-debug.log 19 | package-lock.json 20 | yarn-error.log -------------------------------------------------------------------------------- /.istanbul.yml: -------------------------------------------------------------------------------- 1 | verbose: false 2 | instrumentation: 3 | root: lib 4 | extensions: 5 | - .ts 6 | # default-excludes: true 7 | # excludes: [] 8 | # variable: __coverage__ 9 | # compact: true 10 | # preserve-comments: false 11 | # complete-copy: false 12 | # save-baseline: false 13 | # baseline-file: ./coverage/coverage-baseline.raw.json 14 | # include-all-sources: false 15 | # include-pid: false 16 | # es-modules: true 17 | # auto-wrap: true 18 | # reporting: 19 | # print: summary 20 | # reports: 21 | # - lcov 22 | # dir: ./coverage 23 | # summarizer: pkg 24 | # report-config: {} 25 | # watermarks: 26 | # statements: [50, 80] 27 | # functions: [50, 80] 28 | # branches: [50, 80] 29 | # lines: [50, 80] 30 | # hooks: 31 | # hook-run-in-context: false 32 | # post-require-hook: null 33 | # handle-sigint: false 34 | # check: 35 | # global: 36 | # statements: 0 37 | # lines: 0 38 | # branches: 0 39 | # functions: 0 40 | # excludes: [] 41 | # each: 42 | # statements: 0 43 | # lines: 0 44 | # branches: 0 45 | # functions: 0 46 | # excludes: [] 47 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 140, 3 | "tabWidth": 4, 4 | "useTabs": false, 5 | "semi": true, 6 | "singleQuote": false, 7 | "trailingComma": "none", 8 | "bracketSpacing": true, 9 | "overrides": [ 10 | { 11 | "files": "*.js", 12 | "options": { 13 | "tabWidth": 2 14 | } 15 | }, 16 | { 17 | "files": "*.json", 18 | "options": { 19 | "tabWidth": 2 20 | } 21 | }, 22 | { 23 | "files": ".prettierrc", 24 | "options": { 25 | "tabWidth": 2 26 | } 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /.publishrc: -------------------------------------------------------------------------------- 1 | { 2 | "validations": { 3 | "vulnerableDependencies": false, 4 | "uncommittedChanges": true, 5 | "untrackedFiles": true, 6 | "sensitiveData": true, 7 | "branch": "master", 8 | "gitTag": true 9 | }, 10 | "confirm": true, 11 | "publishTag": "latest --access public", 12 | "prePublishScript": false, 13 | "postPublishScript": false 14 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "typescript.tsdk": "node_modules/typescript/lib", 4 | "tslint.configFile": "tslint.test.json", 5 | 6 | // Set the default 7 | "editor.formatOnSave": false, 8 | 9 | // Enable per-language 10 | "[html]": { 11 | "editor.formatOnSave": true 12 | }, 13 | 14 | "[json]": { 15 | "editor.formatOnSave": true 16 | }, 17 | 18 | "[javascript]": { 19 | "editor.formatOnSave": true 20 | }, 21 | 22 | "[typescript]": { 23 | "editor.formatOnSave": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017-present, RobotlegsJS 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. -------------------------------------------------------------------------------- /definitions/pixi.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import { IEvent } from "@robotlegsjs/core"; 4 | 5 | /** 6 | * Augment PIXI module to recognize IEventDispatcher patch. 7 | */ 8 | declare module "pixi.js" { 9 | interface IEventDispatcher { 10 | addEventListener(type: string | symbol, listener: Function, context?: any): void; 11 | hasEventListener(type: string | symbol, listener?: Function): boolean; 12 | removeEventListener(type: string | symbol, listener?: Function, context?: any, once?: boolean): void; 13 | willTrigger(type: string | symbol): boolean; 14 | dispatchEvent(event: IEvent): boolean; 15 | } 16 | 17 | export interface DisplayObject extends IEventDispatcher {} 18 | export interface SystemRenderer extends IEventDispatcher {} 19 | 20 | export interface BaseTexture extends IEventDispatcher {} 21 | export interface Texture extends IEventDispatcher {} 22 | 23 | export interface Container extends DisplayObject { 24 | contains(child: DisplayObject): boolean; 25 | } 26 | 27 | export namespace loaders { 28 | export interface Loader extends IEventDispatcher {} 29 | export interface Resource extends IEventDispatcher {} 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /deploy-example.sh: -------------------------------------------------------------------------------- 1 | yarn build:example 2 | rm -Rf gh-pages 3 | mkdir -p gh-pages 4 | cd gh-pages 5 | git init . 6 | git remote add origin git@github.com:RobotlegsJS/RobotlegsJS-Pixi.git 7 | cp -r ../dist/* . 8 | git checkout -b gh-pages 9 | git add . 10 | git commit -m "update example build" 11 | git push origin gh-pages --force 12 | -------------------------------------------------------------------------------- /example/Game.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import PIXI = require("pixi.js"); 9 | 10 | import { Context, MVCSBundle } from "@robotlegsjs/core"; 11 | import { ContextView, PixiBundle } from "../src"; 12 | 13 | import { MyConfig } from "./config/MyConfig"; 14 | import { RobotlegsView } from "./view/RobotlegsView"; 15 | 16 | export class Game { 17 | private canvas: HTMLCanvasElement; 18 | private stage: PIXI.Container; 19 | private renderer: PIXI.Renderer; 20 | private context: Context; 21 | 22 | constructor() { 23 | this.canvas = document.getElementById("canvas"); 24 | this.renderer = PIXI.autoDetectRenderer({ 25 | width: 960, 26 | height: 400, 27 | view: this.canvas, 28 | backgroundColor: 0xffffff 29 | }); 30 | this.stage = new PIXI.Container(); 31 | 32 | this.context = new Context(); 33 | this.context 34 | .install(MVCSBundle, PixiBundle) 35 | .configure(new ContextView(this.stage)) 36 | .configure(MyConfig) 37 | .initialize(); 38 | 39 | this.stage.addChild(new RobotlegsView()); 40 | 41 | document.body.appendChild(this.renderer.view); 42 | 43 | this.render(); 44 | } 45 | 46 | public render = () => { 47 | this.renderer.render(this.stage); 48 | window.requestAnimationFrame(this.render); 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /example/config/MyConfig.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { inject, injectable, IConfig } from "@robotlegsjs/core"; 9 | 10 | import { IMediatorMap } from "../../src"; 11 | 12 | import { RobotlegsMediator } from "../mediator/RobotlegsMediator"; 13 | import { SmileyMediator } from "../mediator/SmileyMediator"; 14 | 15 | import { RobotlegsView } from "../view/RobotlegsView"; 16 | import { SmileyView } from "../view/SmileyView"; 17 | 18 | @injectable() 19 | export class MyConfig implements IConfig { 20 | @inject(IMediatorMap) 21 | private mediatorMap: IMediatorMap; 22 | 23 | public configure(): void { 24 | this.mediatorMap.map(RobotlegsView).toMediator(RobotlegsMediator); 25 | this.mediatorMap.map(SmileyView).toMediator(SmileyMediator); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /example/index.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | /// 9 | 10 | import "reflect-metadata"; 11 | 12 | import { Game } from "./Game"; 13 | 14 | (window).initGame = () => { 15 | let game: Game = new Game(); 16 | (window).game = game; 17 | }; 18 | -------------------------------------------------------------------------------- /example/mediator/RobotlegsMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Mediator } from "../../src"; 9 | 10 | import { RobotlegsView } from "../view/RobotlegsView"; 11 | import { SmileyView } from "../view/SmileyView"; 12 | 13 | export class RobotlegsMediator extends Mediator { 14 | public initialize(): void { 15 | console.log("CircleMediator initialized!"); 16 | this.view.interactive = true; 17 | this.addViewListener("click", this.onClick, this); 18 | } 19 | 20 | public onClick(e: any): void { 21 | let radius: number = 50 + Math.random() * 50; 22 | this.view.parent.addChild(new SmileyView(radius)); 23 | } 24 | 25 | public destroy(): void { 26 | console.log("CircleMediator destroyed!"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /example/mediator/SmileyMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Mediator } from "../../src"; 9 | 10 | import { SmileyView } from "../view/SmileyView"; 11 | 12 | export class SmileyMediator extends Mediator { 13 | public initialize(): void { 14 | console.log("ChildMediator initialized!"); 15 | this.view.interactive = true; 16 | this.addViewListener("click", this.onClick, this); 17 | } 18 | 19 | public onClick(e: any): void { 20 | this.view.parent.removeChild(this.view); 21 | } 22 | 23 | public destroy(): void { 24 | console.log("ChildMediator destroyed!"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.example.json" 3 | } 4 | -------------------------------------------------------------------------------- /example/view/RobotlegsView.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container, Sprite } from "pixi.js"; 9 | 10 | export class RobotlegsView extends Container { 11 | private robotlegsLogo: Sprite; 12 | 13 | constructor() { 14 | super(); 15 | 16 | this.loadLogo(); 17 | this.move(); 18 | this.enable(); 19 | } 20 | 21 | private loadLogo(): void { 22 | // create a PIXI sprite from an image path 23 | this.robotlegsLogo = Sprite.from("images/robotlegs.png"); 24 | 25 | // add logo 26 | this.addChild(this.robotlegsLogo); 27 | } 28 | 29 | private move(): void { 30 | // center the sprite's anchor point 31 | this.robotlegsLogo.anchor.set(0.5); 32 | 33 | // move the sprite to the center of the canvas 34 | this.robotlegsLogo.x = 960 * 0.5; 35 | this.robotlegsLogo.y = 400 * 0.5; 36 | } 37 | 38 | private enable(): void { 39 | // Opt-in to interactivity 40 | this.interactive = true; 41 | 42 | // Shows hand cursor 43 | this.buttonMode = true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /example/view/SmileyView.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container, Graphics } from "pixi.js"; 9 | 10 | export class SmileyView extends Container { 11 | private _radius: number; 12 | 13 | constructor(radius: number) { 14 | super(); 15 | 16 | this._radius = Math.max(radius, 50); 17 | 18 | this.drawSmiley(); 19 | this.move(); 20 | this.enable(); 21 | } 22 | 23 | private drawSmiley(): void { 24 | let graphics: Graphics = new Graphics(); 25 | 26 | // Head 27 | graphics.lineStyle(8, 0x000000, 1); 28 | graphics.beginFill(0xffcc00); 29 | graphics.drawCircle(0, 0, this._radius); 30 | 31 | // Mouth 32 | graphics.lineStyle(8, 0x000000, 1); 33 | graphics.beginFill(0xffcc00); 34 | graphics.arc(0, 0, this._radius * 0.65, 0, Math.PI, false); 35 | 36 | // Right eye 37 | graphics.lineStyle(8, 0x000000, 1); 38 | graphics.beginFill(0x000000); 39 | graphics.drawCircle(-(this._radius / 3), -(this._radius / 4), this._radius / 8); 40 | 41 | // Left eye 42 | graphics.lineStyle(8, 0x000000, 1); 43 | graphics.beginFill(0x000000); 44 | graphics.drawCircle(this._radius / 3, -(this._radius / 4), this._radius / 8); 45 | 46 | this.addChild(graphics); 47 | } 48 | 49 | private move(): void { 50 | this.x = Math.random() * 960; 51 | this.y = Math.random() * 400; 52 | 53 | this.x = Math.max(this.x, this._radius); 54 | this.x = Math.min(this.x, 960 - this._radius); 55 | 56 | this.y = Math.max(this.y, this._radius); 57 | this.y = Math.min(this.y, 400 - this._radius); 58 | } 59 | 60 | private enable(): void { 61 | // Opt-in to interactivity 62 | this.interactive = true; 63 | 64 | // Shows hand cursor 65 | this.buttonMode = true; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | const puppeteer = require("puppeteer"); 2 | 3 | process.env.TEST = true; 4 | process.env.NODE_ENV = "test"; 5 | process.env.CHROME_BIN = puppeteer.executablePath(); 6 | 7 | const webpackConfig = require("./webpack.config.js")({ production: false, karma: true }); 8 | 9 | delete webpackConfig.entry; 10 | 11 | module.exports = config => { 12 | "use strict"; 13 | 14 | var configuration = { 15 | client: { 16 | mocha: { 17 | timeout: 5000 18 | } 19 | }, 20 | basePath: "", 21 | frameworks: ["mocha", "sinon-chai", "es6-shim"], 22 | files: [ 23 | { pattern: "node_modules/reflect-metadata/Reflect.js", include: true }, 24 | { pattern: "node_modules/bluebird/js/browser/bluebird.js", include: true }, 25 | { pattern: "./test/index.ts", include: true }, 26 | { pattern: "**/*.map", served: true, included: false, watched: true } 27 | ], 28 | preprocessors: { 29 | "./test/index.ts": ["webpack"], 30 | "./**/**/**/**.ts": ["sourcemap"] 31 | }, 32 | webpack: webpackConfig, 33 | webpackMiddleware: { 34 | noInfo: true 35 | }, 36 | plugins: [ 37 | "karma-webpack", 38 | "karma-sourcemap-writer", 39 | "karma-sourcemap-loader", 40 | "karma-mocha-reporter", 41 | "karma-mocha", 42 | "karma-sinon-chai", 43 | "karma-es6-shim", 44 | "karma-coverage-istanbul-reporter" 45 | ], 46 | mime: { 47 | "text/x-typescript": ["ts", "tsx"] 48 | }, 49 | reporters: config.singleRun ? ["dots", "mocha", "coverage-istanbul"] : ["dots", "mocha"], 50 | coverageIstanbulReporter: { 51 | reports: ["html", "lcov", "lcovonly", "text-summary"], 52 | dir: "coverage", 53 | fixWebpackSourcePaths: true, 54 | "report-config": { 55 | html: { 56 | subdir: "html-report" 57 | } 58 | } 59 | }, 60 | port: 9876, 61 | colors: true, 62 | logLevel: config.LOG_INFO, 63 | autoWatch: true, 64 | concurrency: Infinity, 65 | browsers: [], 66 | browserNoActivityTimeout: 50000 67 | }; 68 | 69 | if (process.env.TRAVIS) { 70 | configuration.browsers.push("ChromeHeadless"); 71 | configuration.plugins.push("karma-chrome-launcher"); 72 | } else { 73 | configuration.browsers.push("ChromeHeadless"); 74 | configuration.plugins.push("karma-chrome-launcher"); 75 | } 76 | 77 | config.set(configuration); 78 | }; 79 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@robotlegsjs/pixi", 3 | "version": "2.0.0", 4 | "description": "PIXI View Integration with RobotlegsJS", 5 | "main": "lib/index.js", 6 | "typings": "lib/index.d.ts", 7 | "scripts": { 8 | "start": "webpack-dev-server --config ./webpack.example.config.js", 9 | "test": "node --max-old-space-size=2048 node_modules/.bin/karma start --single-run", 10 | "mocha": "mocha test/**/*.test.ts --require ts-node/register", 11 | "autoformat": "prettier --config .prettierrc --write --list-different \"{src,static,test,example,definitions}{/**/,/}*.{html,css,js,json,ts}\"", 12 | "tslint-check:src": "tslint-config-prettier-check ./tslint.json", 13 | "tslint-check:test": "tslint-config-prettier-check ./tslint.test.json", 14 | "tslint-check:example": "tslint-config-prettier-check ./tslint.example.json", 15 | "tslint:src": "tslint --project tsconfig.json", 16 | "tslint:test": "tslint --config tslint.test.json --project tsconfig.test.json", 17 | "tslint:example": "tslint --config tslint.example.json --project tsconfig.example.json", 18 | "tslint": "npm run tslint-check:src && npm run tslint-check:test && npm run tslint-check:example && npm run tslint:src && npm run tslint:test && npm run tslint:example", 19 | "clean-up": "rimraf .nyc_output && rimraf coverage && rimraf lib && rimraf lib-test && rimraf lib-example && rimraf dist && rimraf dist-test", 20 | "compile:src": "tsc -d --importHelpers", 21 | "compile:test": "tsc -p tsconfig.test.json -d --importHelpers", 22 | "compile:example": "tsc -p tsconfig.example.json -d --importHelpers", 23 | "dev": "webpack", 24 | "build": "webpack --env.production", 25 | "build:example": "webpack --config ./webpack.example.config.js --env.production", 26 | "deploy:example": "./deploy-example.sh", 27 | "prepare": "npm run clean-up && npm run compile:src", 28 | "prepublishOnly": "publish-please guard", 29 | "publish-please": "npm run tslint && npm run autoformat && npm run clean-up && npm run test && publish-please" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "git@github.com:RobotlegsJS/RobotlegsJS-Pixi.git" 34 | }, 35 | "publishConfig": { 36 | "registry": "https://registry.npmjs.org" 37 | }, 38 | "keywords": [ 39 | "TypeScript", 40 | "Robotlegs", 41 | "IoC", 42 | "PIXI" 43 | ], 44 | "author": "RobotlegsJS", 45 | "contributors": [ 46 | "Bùi Việt Thành ", 47 | "Endel Dreyer ", 48 | "Mateusz Szymik ", 49 | "Tiago Schenkel " 50 | ], 51 | "license": "MIT", 52 | "bugs": { 53 | "url": "https://github.com/RobotlegsJS/RobotlegsJS-Pixi/issues" 54 | }, 55 | "homepage": "https://github.com/RobotlegsJS/RobotlegsJS-Pixi#readme", 56 | "files": [ 57 | "definitions", 58 | "lib" 59 | ], 60 | "directories": { 61 | "lib": "./lib" 62 | }, 63 | "dependencies": { 64 | "@robotlegsjs/core": "^2.0.0", 65 | "tslib": "^1.11.1" 66 | }, 67 | "peerDependencies": { 68 | "pixi.js": "^5.0.0", 69 | "reflect-metadata": "^0.1.13" 70 | }, 71 | "devDependencies": { 72 | "@types/bluebird": "^3.5.30", 73 | "@types/chai": "^4.2.11", 74 | "@types/mocha": "^7.0.2", 75 | "@types/sinon": "^7.5.2", 76 | "@types/webpack-env": "^1.15.1", 77 | "bluebird": "^3.7.2", 78 | "browserify-versionify": "^1.0.6", 79 | "chai": "^4.2.0", 80 | "clean-webpack-plugin": "^3.0.0", 81 | "copy-webpack-plugin": "^5.1.1", 82 | "es6-map": "^0.1.5", 83 | "es6-symbol": "^3.1.3", 84 | "glslify": "^7.0.0", 85 | "html-webpack-plugin": "^3.2.0", 86 | "imports-loader": "^0.8.0", 87 | "istanbul-instrumenter-loader": "^3.0.1", 88 | "karma": "^4.4.1", 89 | "karma-chrome-launcher": "^3.1.0", 90 | "karma-coverage-istanbul-reporter": "^2.1.1", 91 | "karma-es6-shim": "^1.0.0", 92 | "karma-mocha": "^1.3.0", 93 | "karma-mocha-reporter": "^2.2.5", 94 | "karma-sinon-chai": "^2.0.2", 95 | "karma-sourcemap-loader": "^0.3.7", 96 | "karma-sourcemap-writer": "^0.1.2", 97 | "karma-webpack": "^4.0.2", 98 | "mocha": "^7.1.0", 99 | "pixi.js": "^5.2.1", 100 | "prettier": "^1.19.1", 101 | "publish-please": "^5.5.1", 102 | "puppeteer": "^2.1.1", 103 | "reflect-metadata": "^0.1.13", 104 | "rimraf": "^3.0.2", 105 | "sinon": "^9.0.1", 106 | "sinon-chai": "^3.5.0", 107 | "terser-webpack-plugin": "^2.3.5", 108 | "ts-loader": "^6.2.1", 109 | "ts-node": "^8.6.2", 110 | "tslint": "^6.1.0", 111 | "tslint-config-prettier": "^1.18.0", 112 | "typescript": "^3.8.3", 113 | "webpack": "^4.42.0", 114 | "webpack-cli": "^3.3.11", 115 | "webpack-dev-server": "^3.10.3", 116 | "webpack-simple-progress-plugin": "^0.0.4" 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | // ContextView 9 | export { IContextView } from "./robotlegs/bender/extensions/contextView/api/IContextView"; 10 | export { ContextView } from "./robotlegs/bender/extensions/contextView/impl/ContextView"; 11 | export { ContextViewListenerConfig } from "./robotlegs/bender/extensions/contextView/impl/ContextViewListenerConfig"; 12 | export { ContextViewExtension } from "./robotlegs/bender/extensions/contextView/ContextViewExtension"; 13 | 14 | // MediatorMap 15 | export { IMediator } from "./robotlegs/bender/extensions/mediatorMap/api/IMediator"; 16 | export { IMediatorMap } from "./robotlegs/bender/extensions/mediatorMap/api/IMediatorMap"; 17 | export { IMediatorMapping } from "./robotlegs/bender/extensions/mediatorMap/api/IMediatorMapping"; 18 | export { Mediator } from "./robotlegs/bender/extensions/mediatorMap/impl/Mediator"; 19 | export { MediatorMapExtension } from "./robotlegs/bender/extensions/mediatorMap/MediatorMapExtension"; 20 | 21 | // ViewManager 22 | export { IViewHandler } from "./robotlegs/bender/extensions/viewManager/api/IViewHandler"; 23 | export { IViewManager } from "./robotlegs/bender/extensions/viewManager/api/IViewManager"; 24 | export { ManualStageObserverExtension } from "./robotlegs/bender/extensions/viewManager/ManualStageObserverExtension"; 25 | export { StageCrawlerExtension } from "./robotlegs/bender/extensions/viewManager/StageCrawlerExtension"; 26 | export { StageObserverExtension } from "./robotlegs/bender/extensions/viewManager/StageObserverExtension"; 27 | export { ViewManagerExtension } from "./robotlegs/bender/extensions/viewManager/ViewManagerExtension"; 28 | 29 | /** 30 | * Bundles 31 | */ 32 | export { PixiBundle } from "./robotlegs/bender/bundles/pixi/PixiBundle"; 33 | -------------------------------------------------------------------------------- /src/robotlegs/bender/bundles/pixi/PixiBundle.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IBundle, IContext, ILogger, instanceOfType } from "@robotlegsjs/core"; 9 | 10 | import { IContextView } from "../../extensions/contextView/api/IContextView"; 11 | import { ContextView } from "../../extensions/contextView/impl/ContextView"; 12 | import { ContextViewListenerConfig } from "../../extensions/contextView/impl/ContextViewListenerConfig"; 13 | 14 | import { ContextViewExtension } from "../../extensions/contextView/ContextViewExtension"; 15 | import { MediatorMapExtension } from "../../extensions/mediatorMap/MediatorMapExtension"; 16 | import { StageCrawlerExtension } from "../../extensions/viewManager/StageCrawlerExtension"; 17 | import { StageObserverExtension } from "../../extensions/viewManager/StageObserverExtension"; 18 | import { ViewManagerExtension } from "../../extensions/viewManager/ViewManagerExtension"; 19 | 20 | /** 21 | * For that Classic Robotlegs flavour 22 | * 23 | *

This bundle installs a number of extensions commonly used 24 | * in typical Robotlegs applications and modules.

25 | */ 26 | export class PixiBundle implements IBundle { 27 | /*============================================================================*/ 28 | /* Private Properties */ 29 | /*============================================================================*/ 30 | 31 | private _context: IContext; 32 | private _logger: ILogger; 33 | 34 | /*============================================================================*/ 35 | /* Public Functions */ 36 | /*============================================================================*/ 37 | 38 | /** 39 | * @inheritDoc 40 | */ 41 | public extend(context: IContext): void { 42 | this._context = context; 43 | this._logger = context.getLogger(this); 44 | 45 | this._context.install( 46 | ContextViewExtension, 47 | ViewManagerExtension, 48 | StageObserverExtension, 49 | MediatorMapExtension, 50 | StageCrawlerExtension 51 | ); 52 | 53 | this._context.addConfigHandler(instanceOfType(ContextView), this.handleContextView.bind(this)); 54 | this._context.whenInitializing(this.whenInitializing.bind(this)); 55 | this._context.afterDestroying(this.afterDestroying.bind(this)); 56 | } 57 | 58 | /*============================================================================*/ 59 | /* Private Functions */ 60 | /*============================================================================*/ 61 | 62 | private handleContextView(): void { 63 | this._context.configure(ContextViewListenerConfig); 64 | } 65 | 66 | private whenInitializing(): void { 67 | if (!this._context.injector.isBound(IContextView)) { 68 | this._logger.error("PixiBundle requires IContextView."); 69 | } 70 | } 71 | 72 | private afterDestroying(): void { 73 | this._context = null; 74 | this._logger = null; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/contextView/ContextViewExtension.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { instanceOfType, IContext, IExtension, IInjector, ILogger } from "@robotlegsjs/core"; 9 | 10 | import { IContextView } from "./api/IContextView"; 11 | import { ContextView } from "./impl/ContextView"; 12 | 13 | import { applyPixiPatch } from "./pixiPatch/pixi-patch"; 14 | 15 | /** 16 | *

This Extension waits for a ContextView to be added as a configuration 17 | * and maps it into the context's injector.

18 | * 19 | *

It should be installed before context initialization.

20 | */ 21 | export class ContextViewExtension implements IExtension { 22 | /*============================================================================*/ 23 | /* Private Properties */ 24 | /*============================================================================*/ 25 | 26 | private _injector: IInjector; 27 | 28 | private _logger: ILogger; 29 | 30 | /*============================================================================*/ 31 | /* Public Functions */ 32 | /*============================================================================*/ 33 | 34 | /** 35 | * @inheritDoc 36 | */ 37 | public extend(context: IContext): void { 38 | this._injector = context.injector; 39 | this._logger = context.getLogger(this); 40 | context.beforeInitializing(this.beforeInitializing.bind(this)); 41 | context.addConfigHandler(instanceOfType(ContextView), this.handleContextView.bind(this)); 42 | } 43 | 44 | /*============================================================================*/ 45 | /* Private Functions */ 46 | /*============================================================================*/ 47 | 48 | private handleContextView(contextView: IContextView): void { 49 | if (this._injector.isBound(IContextView)) { 50 | this._logger.warn("A contextView has already been installed, ignoring {0}", [contextView.view]); 51 | } else { 52 | this._logger.debug("Mapping {0} as contextView", [contextView.view]); 53 | 54 | applyPixiPatch(contextView.view); 55 | 56 | this._injector.bind(IContextView).toConstantValue(contextView); 57 | } 58 | } 59 | 60 | private beforeInitializing(): void { 61 | if (!this._injector.isBound(IContextView)) { 62 | this._logger.error("A ContextView must be installed if you install the ContextViewExtension."); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/contextView/api/IContextView.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container } from "pixi.js"; 9 | 10 | export let IContextView = Symbol("IContextView"); 11 | export interface IContextView { 12 | view: Container; 13 | } 14 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/contextView/impl/ContextView.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container } from "pixi.js"; 9 | 10 | import { IConfig } from "@robotlegsjs/core"; 11 | 12 | import { IContextView } from "../api/IContextView"; 13 | 14 | /** 15 | * The Context View represents the root Container for a Context 16 | */ 17 | export class ContextView implements IContextView, IConfig { 18 | private _view: Container; 19 | 20 | /*============================================================================*/ 21 | /* Constructor */ 22 | /*============================================================================*/ 23 | 24 | /** 25 | * The Context View represents the root Container for a Context 26 | * @param view The root Container for this Context 27 | */ 28 | constructor(view: Container) { 29 | if (view !== null && view !== undefined) { 30 | this._view = view; 31 | } else { 32 | throw new Error("View can't be null or undefined"); 33 | } 34 | } 35 | 36 | /*============================================================================*/ 37 | /* Public Properties */ 38 | /*============================================================================*/ 39 | 40 | /** 41 | * 42 | */ 43 | public configure(): void {} 44 | 45 | /** 46 | * The root Container for this Context 47 | */ 48 | public get view(): Container { 49 | return this._view; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/contextView/impl/ContextViewListenerConfig.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject, IConfig } from "@robotlegsjs/core"; 9 | 10 | import { IContextView } from "../api/IContextView"; 11 | import { IViewManager } from "../../viewManager/api/IViewManager"; 12 | 13 | /** 14 | * This configuration file adds the ContextView to the viewManager. 15 | * 16 | * It requires that the ViewManagerExtension, ContextViewExtension 17 | * and a ContextView have been installed. 18 | */ 19 | @injectable() 20 | export class ContextViewListenerConfig implements IConfig { 21 | /*============================================================================*/ 22 | /* Public Properties */ 23 | /*============================================================================*/ 24 | 25 | private _contextView: IContextView; 26 | 27 | private _viewManager: IViewManager; 28 | 29 | /*============================================================================*/ 30 | /* Public Functions */ 31 | /*============================================================================*/ 32 | 33 | constructor(@inject(IContextView) contextView: IContextView, @inject(IViewManager) viewManager: IViewManager) { 34 | this._contextView = contextView; 35 | this._viewManager = viewManager; 36 | } 37 | 38 | /** 39 | * @inheritDoc 40 | */ 41 | public configure(): void { 42 | // Adds the Context View to the View Manager at startup 43 | this._viewManager.addContainer(this._contextView.view); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/contextView/pixiPatch/contains-patch.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | /** 9 | * Patch PIXI.Container class to add implementation of contains method. 10 | */ 11 | 12 | import { Container, DisplayObject } from "pixi.js"; 13 | 14 | const ContainerMixin = { 15 | /** 16 | * Determines whether the specified child object is a child of the Container instance or the instance itself. 17 | * The search includes the entire display list including this Container instance. 18 | * Grandchildren, great-grandchildren, and so on each return true. 19 | * 20 | * @param child The child object to test. 21 | * 22 | * @return true if the child object is a child of the Container or the Container itself; otherwise false. 23 | * 24 | * @see {@link https://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html#contains()} 25 | */ 26 | contains(this: Container, child: DisplayObject): boolean { 27 | let found: boolean = false; 28 | if (this === child || this.children.indexOf(child) >= 0) { 29 | found = true; 30 | } else { 31 | for (let c of this.children) { 32 | if (c instanceof Container && c.contains(child)) { 33 | found = true; 34 | break; 35 | } 36 | } 37 | } 38 | return found; 39 | } 40 | }; 41 | 42 | Object.assign(Container.prototype, ContainerMixin); 43 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/contextView/pixiPatch/eventemitter3-patch.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | /** 9 | * Patch PIXI event handling. 10 | * 11 | * - Proxy PIXI events to be compatible with EventDispatcher 12 | * - Implements event bubbling on `dispatchEvent` when `bubbles` is true. 13 | */ 14 | 15 | import { DisplayObject, utils } from "pixi.js"; 16 | import EventEmitter = utils.EventEmitter; 17 | import { IEvent } from "@robotlegsjs/core"; 18 | 19 | const EventDispatcherMixin = { 20 | addEventListener(this: EventEmitter, type: string | symbol, listener: Function, context?: any): void { 21 | this.on(type, listener, context); 22 | }, 23 | 24 | hasEventListener(this: EventEmitter, type: string | symbol, listener?: Function): boolean { 25 | return this.listenerCount(type) > 0; 26 | }, 27 | 28 | removeEventListener(this: EventEmitter, type: string | symbol, listener?: Function, context?: any, once?: boolean): void { 29 | this.off(type, listener, context, once); 30 | }, 31 | 32 | willTrigger(type: string | symbol): boolean { 33 | return this.hasEventListener(type); 34 | }, 35 | 36 | dispatchEvent(this: EventEmitter, event: IEvent): void { 37 | event.target = this; 38 | 39 | let currentTarget = this; 40 | do { 41 | event.currentTarget = currentTarget; 42 | event.currentTarget.emit(event.type, event); 43 | currentTarget = (currentTarget as DisplayObject).parent; 44 | } while (currentTarget && event.bubbles); 45 | } 46 | }; 47 | 48 | Object.assign(DisplayObject.prototype, EventDispatcherMixin); 49 | Object.assign(EventEmitter.prototype, EventDispatcherMixin); 50 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/contextView/pixiPatch/pixi-patch.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | /** 9 | * Patch PIXI to: 10 | * - emit "added"/"removed" events on stage 11 | * - implement PIXI.Container.contains method 12 | */ 13 | 14 | import "./eventemitter3-patch"; 15 | import "./contains-patch"; 16 | 17 | import PIXI = require("pixi.js"); 18 | 19 | function isConnectedToStage(stage: PIXI.Container, object: PIXI.DisplayObject): boolean { 20 | if (object === stage) { 21 | return true; 22 | } else if (object.parent) { 23 | return isConnectedToStage(stage, object.parent); 24 | } else { 25 | return false; 26 | } 27 | } 28 | 29 | function emitAddedEvent(stage: PIXI.Container, target: PIXI.DisplayObject): void { 30 | stage.emit("added", { target }); 31 | 32 | if (target instanceof PIXI.Container) { 33 | target.children.forEach(child => emitAddedEvent(stage, child)); 34 | } 35 | } 36 | 37 | function emitRemovedEvent(stage: PIXI.Container, target: PIXI.DisplayObject): void { 38 | stage.emit("removed", { target }); 39 | 40 | if (target instanceof PIXI.Container) { 41 | target.children.forEach(child => emitRemovedEvent(stage, child)); 42 | } 43 | } 44 | 45 | export function applyPixiPatch(stage: PIXI.Container) { 46 | let addChild = PIXI.Container.prototype.addChild; 47 | let addChildAt = PIXI.Container.prototype.addChildAt; 48 | let removeChild = PIXI.Container.prototype.removeChild; 49 | let removeChildren = PIXI.Container.prototype.removeChildren; 50 | let removeChildAt = PIXI.Container.prototype.removeChildAt; 51 | 52 | PIXI.Container.prototype.addChild = function patchedAddChild(/*...children: T*/): T[0] { 53 | for (let i = 0, len = arguments.length; i < len; i++) { 54 | const object = arguments[i]; 55 | addChild.call(this, object); 56 | 57 | if (isConnectedToStage(stage, object)) { 58 | emitAddedEvent(stage, object); 59 | } 60 | } 61 | return arguments[0]; 62 | }; 63 | 64 | PIXI.Container.prototype.addChildAt = function patchedAddChildAt(child: T, index: number): T { 65 | addChildAt.call(this, child, index); 66 | 67 | if (isConnectedToStage(stage, child)) { 68 | emitAddedEvent(stage, child); 69 | } 70 | 71 | return child; 72 | }; 73 | 74 | PIXI.Container.prototype.removeChild = function patchedRemoveChild(/*...children: T*/): T[0] { 75 | for (let i = 0, len = arguments.length; i < len; i++) { 76 | const object = arguments[i]; 77 | if (isConnectedToStage(stage, object)) { 78 | emitRemovedEvent(stage, object); 79 | } 80 | 81 | removeChild.call(this, object); 82 | } 83 | 84 | return arguments[0]; 85 | }; 86 | 87 | PIXI.Container.prototype.removeChildren = function patchedRemoveChildren( 88 | beginIndex: number = 0, 89 | endIndex?: number 90 | ): T[] { 91 | let removedChildren = removeChildren.call(this, beginIndex, endIndex); 92 | 93 | if (isConnectedToStage(stage, this) && removedChildren.length) { 94 | for (let child of removedChildren) { 95 | emitRemovedEvent(stage, child); 96 | } 97 | } 98 | 99 | return removedChildren; 100 | }; 101 | 102 | PIXI.Container.prototype.removeChildAt = function patchedRemoveChildAt( 103 | index: number 104 | ): T { 105 | let child = removeChildAt.call(this, index); 106 | 107 | if (isConnectedToStage(stage, this) && child) { 108 | emitRemovedEvent(stage, child); 109 | } 110 | 111 | return child; 112 | }; 113 | } 114 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/MediatorMapExtension.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IContext, IExtension, IInjector } from "@robotlegsjs/core"; 9 | 10 | import { IMediatorMap } from "./api/IMediatorMap"; 11 | import { MediatorMap } from "./impl/MediatorMap"; 12 | 13 | import { IViewManager } from "../viewManager/api/IViewManager"; 14 | 15 | /** 16 | * This extension installs a shared IMediatorMap into the context 17 | */ 18 | export class MediatorMapExtension implements IExtension { 19 | /*============================================================================*/ 20 | /* Private Properties */ 21 | /*============================================================================*/ 22 | 23 | private _injector: IInjector; 24 | 25 | private _mediatorMap: MediatorMap; 26 | 27 | private _viewManager: IViewManager; 28 | 29 | /*============================================================================*/ 30 | /* Public Functions */ 31 | /*============================================================================*/ 32 | 33 | /** 34 | * @inheritDoc 35 | */ 36 | public extend(context: IContext): void { 37 | context 38 | .beforeInitializing(this.beforeInitializing.bind(this)) 39 | .beforeDestroying(this.beforeDestroying.bind(this)) 40 | .whenDestroying(this.whenDestroying.bind(this)); 41 | this._injector = context.injector; 42 | this._injector 43 | .bind(IMediatorMap) 44 | .to(MediatorMap) 45 | .inSingletonScope(); 46 | } 47 | 48 | /*============================================================================*/ 49 | /* Private Functions */ 50 | /*============================================================================*/ 51 | 52 | private beforeInitializing(): void { 53 | this._mediatorMap = this._injector.get(IMediatorMap); 54 | 55 | if (this._injector.isBound(IViewManager)) { 56 | this._viewManager = this._injector.get(IViewManager); 57 | this._viewManager.addViewHandler(this._mediatorMap); 58 | } 59 | } 60 | 61 | private beforeDestroying(): void { 62 | this._mediatorMap.unmediateAll(); 63 | 64 | if (this._injector.isBound(IViewManager)) { 65 | this._viewManager = this._injector.get(IViewManager); 66 | this._viewManager.removeViewHandler(this._mediatorMap); 67 | } 68 | } 69 | 70 | private whenDestroying(): void { 71 | if (this._injector.isBound(IMediatorMap)) { 72 | this._injector.unbind(IMediatorMap); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/api/IMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | /** 9 | * Optional Mediator interface 10 | */ 11 | export interface IMediator { 12 | /** 13 | * Initializes the mediator. This is run automatically by the mediatorMap when a mediator is created. 14 | * Normally the initialize function is where you would add handlers using the eventMap. 15 | */ 16 | initialize(): void; 17 | 18 | /** 19 | * Destroys the mediator. This is run automatically by the mediatorMap when a mediator is destroyed. 20 | * You should clean up any handlers that were added directly (eventMap handlers will be cleaned up automatically). 21 | */ 22 | destroy(): void; 23 | } 24 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/api/IMediatorMap.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IClass, ITypeMatcher } from "@robotlegsjs/core"; 9 | 10 | import { IMediatorMapper } from "../dsl/IMediatorMapper"; 11 | import { IMediatorUnmapper } from "../dsl/IMediatorUnmapper"; 12 | 13 | /** 14 | * The Mediator Map allows you to bind Mediators to objects 15 | */ 16 | export let IMediatorMap = Symbol("IMediatorMap"); 17 | export interface IMediatorMap { 18 | /** 19 | * Maps a matcher that will be tested against incoming items to be handled. 20 | * @param matcher The type or package matcher specifying the rules for matching. 21 | * @return the mapper so that you can continue the mapping. 22 | */ 23 | mapMatcher(matcher: ITypeMatcher): IMediatorMapper; 24 | 25 | /** 26 | * Maps a type that will be tested against incoming items to be handled. 27 | * Under the hood this will create a TypeMatcher for this type. 28 | * @param type The class or interface to be matched against. 29 | * @return the mapper so that you can continue the mapping. 30 | */ 31 | map(type: IClass): IMediatorMapper; 32 | 33 | /** 34 | * Removes a mapping that was made against a matcher. 35 | * No error will be thrown if there isn't a mapping to remove. 36 | * @param matcher The type or package matcher specifying the rules for matching. 37 | * @return the unmapper so that you can continue the unmapping. 38 | */ 39 | unmapMatcher(matcher: ITypeMatcher): IMediatorUnmapper; 40 | 41 | /** 42 | * Removes a mapping that was made against a type. 43 | * No error will be thrown if there isn't a mapping to remove. 44 | * @param type The class or interface to be matched against. 45 | * @return the unmapper so that you can continue the unmapping. 46 | */ 47 | unmap(type: IClass): IMediatorUnmapper; 48 | 49 | /** 50 | * Mediates an item directly. If the item matches any mapped matchers or types then it will be mediated according to those mappings. 51 | * @param item The item to create mediators for. 52 | */ 53 | mediate(item: any): void; 54 | 55 | /** 56 | * Removes the mediators for an item if there are any. 57 | * @param item The item to remove mediators for. 58 | */ 59 | unmediate(item: any): void; 60 | 61 | /** 62 | * Removes all mediators 63 | */ 64 | unmediateAll(): void; 65 | } 66 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/api/IMediatorMapping.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IClass, ITypeFilter } from "@robotlegsjs/core"; 9 | 10 | /** 11 | * Represents a Mediator mapping 12 | */ 13 | export interface IMediatorMapping { 14 | /** 15 | * The matcher for this mapping 16 | */ 17 | matcher: ITypeFilter; 18 | 19 | /** 20 | * The concrete mediator class 21 | */ 22 | mediatorClass: IClass; 23 | 24 | /** 25 | * A list of guards to check before allowing mediator creation 26 | */ 27 | guards: any[]; 28 | 29 | /** 30 | * A list of hooks to run before creating a mediator 31 | */ 32 | hooks: any[]; 33 | 34 | /** 35 | * Should the mediator be removed when the mediated item looses scope? 36 | */ 37 | autoRemoveEnabled: boolean; 38 | } 39 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/dsl/IMediatorConfigurator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | /** 9 | * Configures a mediator mapping 10 | */ 11 | export interface IMediatorConfigurator { 12 | /** 13 | * Guards to check before allowing a mediator to be created 14 | * @param guards Guards 15 | * @return Self 16 | */ 17 | withGuards(...guards: any[]): IMediatorConfigurator; 18 | 19 | /** 20 | * Hooks to run before a mediator is created 21 | * @param hooks Hooks 22 | * @return Self 23 | */ 24 | withHooks(...hooks: any[]): IMediatorConfigurator; 25 | 26 | /** 27 | * Should the mediator be removed when the mediated item looses scope? 28 | * 29 | *

Usually this would be when the mediated item is a Display Object 30 | * and it leaves the stage.

31 | * 32 | * @param value Boolean 33 | * @return Self 34 | */ 35 | autoRemove(value: boolean): IMediatorConfigurator; 36 | } 37 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/dsl/IMediatorMapper.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IClass } from "@robotlegsjs/core"; 9 | 10 | import { IMediatorConfigurator } from "./IMediatorConfigurator"; 11 | 12 | /** 13 | * Maps a matcher to a concrete Mediator class 14 | */ 15 | export interface IMediatorMapper { 16 | /** 17 | * Maps a matcher to a concrete Mediator class 18 | * @param mediatorClass The concrete mediator class 19 | * @return Mapping configurator 20 | */ 21 | toMediator(mediatorClass: IClass): IMediatorConfigurator; 22 | } 23 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/dsl/IMediatorUnmapper.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IClass } from "@robotlegsjs/core"; 9 | 10 | /** 11 | * Unmaps a Mediator 12 | */ 13 | export interface IMediatorUnmapper { 14 | /** 15 | * Unmaps a mediator from this matcher 16 | * @param mediatorClass Mediator to unmap 17 | */ 18 | fromMediator(mediatorClass: IClass): void; 19 | 20 | /** 21 | * Unmaps all mediator mappings for this matcher 22 | */ 23 | fromAll(): void; 24 | } 25 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/impl/MediatorManager.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { DisplayObject } from "pixi.js"; 9 | 10 | import { IMediatorMapping } from "../api/IMediatorMapping"; 11 | import { MediatorFactory } from "./MediatorFactory"; 12 | 13 | /** 14 | * @private 15 | */ 16 | export class MediatorManager { 17 | /*============================================================================*/ 18 | /* Private Properties */ 19 | /*============================================================================*/ 20 | 21 | private _factory: MediatorFactory; 22 | 23 | /*============================================================================*/ 24 | /* Constructor */ 25 | /*============================================================================*/ 26 | 27 | /** 28 | * @private 29 | */ 30 | constructor(factory: MediatorFactory) { 31 | this._factory = factory; 32 | } 33 | 34 | /*============================================================================*/ 35 | /* Public Functions */ 36 | /*============================================================================*/ 37 | 38 | /** 39 | * @private 40 | */ 41 | public addMediator(mediator: any, item: any, mapping: IMediatorMapping): void { 42 | // Watch Display Object for removal 43 | if (item instanceof DisplayObject && mapping.autoRemoveEnabled) { 44 | (item)._onRemovedFromStage = this.onRemovedFromStage.bind(this, item); 45 | item.on("removed", (item)._onRemovedFromStage, this); 46 | } 47 | 48 | // Synchronize with item life-cycle 49 | this.initializeMediator(mediator, item); 50 | } 51 | 52 | /** 53 | * @private 54 | */ 55 | public removeMediator(mediator: any, item: any, mapping: IMediatorMapping): void { 56 | if (item instanceof DisplayObject) { 57 | item.off("removed", (item)._onRemovedFromStage); 58 | } 59 | 60 | this.destroyMediator(mediator); 61 | } 62 | 63 | /*============================================================================*/ 64 | /* Private Functions */ 65 | /*============================================================================*/ 66 | 67 | private onRemovedFromStage(displayObject: any, fromContainer: any): void { 68 | this._factory.removeMediators(displayObject); 69 | } 70 | 71 | private initializeMediator(mediator: any, mediatedItem: any): void { 72 | if ("preInitialize" in mediator) { 73 | mediator.preInitialize(); 74 | } 75 | 76 | if ("view" in mediator) { 77 | mediator.view = mediatedItem; 78 | } 79 | 80 | if ("initialize" in mediator) { 81 | mediator.initialize(); 82 | } 83 | 84 | if ("postInitialize" in mediator) { 85 | mediator.postInitialize(); 86 | } 87 | } 88 | 89 | private destroyMediator(mediator: any): void { 90 | if ("preDestroy" in mediator) { 91 | mediator.preDestroy(); 92 | } 93 | 94 | if ("destroy" in mediator) { 95 | mediator.destroy(); 96 | } 97 | 98 | if ("view" in mediator) { 99 | mediator.view = null; 100 | } 101 | 102 | if ("postDestroy" in mediator) { 103 | mediator.postDestroy(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMap.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { DisplayObject } from "pixi.js"; 9 | 10 | import { injectable, inject, IClass, IContext, ILogger, ITypeMatcher, TypeMatcher } from "@robotlegsjs/core"; 11 | 12 | import { IMediatorMap } from "../api/IMediatorMap"; 13 | import { IMediatorMapper } from "../dsl/IMediatorMapper"; 14 | import { IMediatorUnmapper } from "../dsl/IMediatorUnmapper"; 15 | 16 | import { IViewHandler } from "../../viewManager/api/IViewHandler"; 17 | 18 | import { MediatorFactory } from "./MediatorFactory"; 19 | import { MediatorViewHandler } from "./MediatorViewHandler"; 20 | import { NullMediatorUnmapper } from "./NullMediatorUnmapper"; 21 | import { MediatorMapper } from "./MediatorMapper"; 22 | 23 | /** 24 | * @private 25 | */ 26 | @injectable() 27 | export class MediatorMap implements IMediatorMap, IViewHandler { 28 | /*============================================================================*/ 29 | /* Private Properties */ 30 | /*============================================================================*/ 31 | 32 | private _mappers: Map = new Map(); 33 | 34 | private _logger: ILogger; 35 | 36 | private _factory: MediatorFactory; 37 | 38 | private _viewHandler: MediatorViewHandler; 39 | 40 | private NULL_UNMAPPER: IMediatorUnmapper = new NullMediatorUnmapper(); 41 | 42 | /*============================================================================*/ 43 | /* Constructor */ 44 | /*============================================================================*/ 45 | 46 | /** 47 | * @private 48 | */ 49 | constructor(@inject(IContext) context: IContext) { 50 | this._logger = context.getLogger(this); 51 | this._factory = new MediatorFactory(context.injector); 52 | this._viewHandler = new MediatorViewHandler(this._factory); 53 | } 54 | 55 | /*============================================================================*/ 56 | /* Public Functions */ 57 | /*============================================================================*/ 58 | 59 | /** 60 | * @inheritDoc 61 | */ 62 | public mapMatcher(matcher: ITypeMatcher): IMediatorMapper { 63 | const desc = matcher.createTypeFilter().descriptor; 64 | let mapper = this._mappers.get(desc); 65 | 66 | if (mapper) { 67 | return mapper; 68 | } 69 | 70 | mapper = this.createMapper(matcher); 71 | this._mappers.set(desc, mapper); 72 | return mapper; 73 | } 74 | 75 | /** 76 | * @inheritDoc 77 | */ 78 | public map(type: IClass): IMediatorMapper { 79 | return this.mapMatcher(new TypeMatcher().allOf(type)); 80 | } 81 | 82 | /** 83 | * @inheritDoc 84 | */ 85 | public unmapMatcher(matcher: ITypeMatcher): IMediatorUnmapper { 86 | return this._mappers.get(matcher.createTypeFilter().descriptor) || this.NULL_UNMAPPER; 87 | } 88 | 89 | /** 90 | * @inheritDoc 91 | */ 92 | public unmap(type: IClass): IMediatorUnmapper { 93 | return this.unmapMatcher(new TypeMatcher().allOf(type)); 94 | } 95 | 96 | /** 97 | * @inheritDoc 98 | */ 99 | public handleView(view: DisplayObject, type: IClass): void { 100 | this._viewHandler.handleView(view, type); 101 | } 102 | 103 | /** 104 | * @inheritDoc 105 | */ 106 | public mediate(item: any): void { 107 | this._viewHandler.handleItem(item, >item.constructor); 108 | } 109 | 110 | /** 111 | * @inheritDoc 112 | */ 113 | public unmediate(item: any): void { 114 | this._factory.removeMediators(item); 115 | } 116 | 117 | /** 118 | * @inheritDoc 119 | */ 120 | public unmediateAll(): void { 121 | this._factory.removeAllMediators(); 122 | } 123 | 124 | /*============================================================================*/ 125 | /* Private Functions */ 126 | /*============================================================================*/ 127 | 128 | private createMapper(matcher: ITypeMatcher): MediatorMapper { 129 | return new MediatorMapper(matcher.createTypeFilter(), this._viewHandler, this._logger); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMapper.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IClass, ILogger, ITypeFilter } from "@robotlegsjs/core"; 9 | 10 | import { IMediatorMapping } from "../api/IMediatorMapping"; 11 | import { IMediatorConfigurator } from "../dsl/IMediatorConfigurator"; 12 | import { IMediatorMapper } from "../dsl/IMediatorMapper"; 13 | import { IMediatorUnmapper } from "../dsl/IMediatorUnmapper"; 14 | 15 | import { MediatorViewHandler } from "./MediatorViewHandler"; 16 | import { MediatorMapping } from "./MediatorMapping"; 17 | 18 | /** 19 | * @private 20 | */ 21 | export class MediatorMapper implements IMediatorMapper, IMediatorUnmapper { 22 | /*============================================================================*/ 23 | /* Private Properties */ 24 | /*============================================================================*/ 25 | 26 | private _mappings: Map, IMediatorMapping> = new Map, IMediatorMapping>(); 27 | 28 | private _typeFilter: ITypeFilter; 29 | 30 | private _handler: MediatorViewHandler; 31 | 32 | private _logger: ILogger; 33 | 34 | /*============================================================================*/ 35 | /* Constructor */ 36 | /*============================================================================*/ 37 | 38 | /** 39 | * @private 40 | */ 41 | constructor(typeFilter: ITypeFilter, handler: MediatorViewHandler, logger?: ILogger) { 42 | this._typeFilter = typeFilter; 43 | this._handler = handler; 44 | this._logger = logger; 45 | } 46 | 47 | /*============================================================================*/ 48 | /* Public Functions */ 49 | /*============================================================================*/ 50 | 51 | /** 52 | * @inheritDoc 53 | */ 54 | public toMediator(mediatorClass: IClass): IMediatorConfigurator { 55 | const mapping: IMediatorMapping = this._mappings.get(mediatorClass); 56 | return mapping ? this.overwriteMapping(mapping) : this.createMapping(mediatorClass); 57 | } 58 | 59 | /** 60 | * @inheritDoc 61 | */ 62 | public fromMediator(mediatorClass: IClass): void { 63 | const mapping: IMediatorMapping = this._mappings.get(mediatorClass); 64 | 65 | if (mapping) { 66 | this.deleteMapping(mapping); 67 | } 68 | } 69 | 70 | /** 71 | * @inheritDoc 72 | */ 73 | public fromAll(): void { 74 | this._mappings.forEach(this.deleteMapping, this); 75 | } 76 | 77 | /*============================================================================*/ 78 | /* Private Functions */ 79 | /*============================================================================*/ 80 | 81 | private createMapping(mediatorClass: IClass): MediatorMapping { 82 | let mapping: MediatorMapping = new MediatorMapping(this._typeFilter, mediatorClass); 83 | this._handler.addMapping(mapping); 84 | this._mappings.set(mediatorClass, mapping); 85 | 86 | if (this._logger) { 87 | this._logger.debug("{0} mapped to {1}", [this._typeFilter, mapping]); 88 | } 89 | 90 | return mapping; 91 | } 92 | 93 | private deleteMapping(mapping: IMediatorMapping): void { 94 | this._handler.removeMapping(mapping); 95 | this._mappings.delete(mapping.mediatorClass); 96 | 97 | if (this._logger) { 98 | this._logger.debug("{0} unmapped from {1}", [this._typeFilter, mapping]); 99 | } 100 | } 101 | 102 | private overwriteMapping(mapping: IMediatorMapping): IMediatorConfigurator { 103 | if (this._logger) { 104 | this._logger.warn( 105 | "{0} already mapped to {1}\n" + 106 | 'If you have overridden this mapping intentionally you can use "unmap()" ' + 107 | "prior to your replacement mapping in order to avoid seeing this message.\n", 108 | [this._typeFilter, mapping] 109 | ); 110 | } 111 | this.deleteMapping(mapping); 112 | return this.createMapping(mapping.mediatorClass); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMapping.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IClass, ITypeFilter } from "@robotlegsjs/core"; 9 | 10 | import { IMediatorMapping } from "../api/IMediatorMapping"; 11 | import { IMediatorConfigurator } from "../dsl/IMediatorConfigurator"; 12 | 13 | /** 14 | * @private 15 | */ 16 | export class MediatorMapping implements IMediatorMapping, IMediatorConfigurator { 17 | /*============================================================================*/ 18 | /* Public Properties */ 19 | /*============================================================================*/ 20 | 21 | private _matcher: ITypeFilter; 22 | 23 | /** 24 | * @inheritDoc 25 | */ 26 | public get matcher(): ITypeFilter { 27 | return this._matcher; 28 | } 29 | 30 | private _mediatorClass: IClass; 31 | 32 | /** 33 | * @inheritDoc 34 | */ 35 | public get mediatorClass(): IClass { 36 | return this._mediatorClass; 37 | } 38 | 39 | private _guards: any[] = []; 40 | 41 | /** 42 | * @inheritDoc 43 | */ 44 | public get guards(): any[] { 45 | return this._guards; 46 | } 47 | 48 | private _hooks: any[] = []; 49 | 50 | /** 51 | * @inheritDoc 52 | */ 53 | public get hooks(): any[] { 54 | return this._hooks; 55 | } 56 | 57 | private _autoRemoveEnabled: boolean = true; 58 | 59 | /** 60 | * @inheritDoc 61 | */ 62 | public get autoRemoveEnabled(): boolean { 63 | return this._autoRemoveEnabled; 64 | } 65 | 66 | /*============================================================================*/ 67 | /* Constructor */ 68 | /*============================================================================*/ 69 | 70 | /** 71 | * @private 72 | */ 73 | constructor(matcher: ITypeFilter, mediatorClass: IClass) { 74 | this._matcher = matcher; 75 | this._mediatorClass = mediatorClass; 76 | } 77 | 78 | /*============================================================================*/ 79 | /* Public Functions */ 80 | /*============================================================================*/ 81 | 82 | /** 83 | * @inheritDoc 84 | */ 85 | public withGuards(...guards: any[]): IMediatorConfigurator { 86 | this._guards = this._guards.concat.apply(this._guards, guards); 87 | return this; 88 | } 89 | 90 | /** 91 | * @inheritDoc 92 | */ 93 | public withHooks(...hooks: any[]): IMediatorConfigurator { 94 | this._hooks = this._hooks.concat.apply(this._hooks, hooks); 95 | return this; 96 | } 97 | 98 | /** 99 | * @inheritDoc 100 | */ 101 | public autoRemove(value: boolean = true): IMediatorConfigurator { 102 | this._autoRemoveEnabled = value; 103 | return this; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/impl/MediatorViewHandler.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { DisplayObject } from "pixi.js"; 9 | 10 | import { IClass } from "@robotlegsjs/core"; 11 | 12 | import { IMediatorMapping } from "../api/IMediatorMapping"; 13 | import { IViewHandler } from "../../viewManager/api/IViewHandler"; 14 | 15 | import { MediatorFactory } from "./MediatorFactory"; 16 | 17 | /** 18 | * @private 19 | */ 20 | export class MediatorViewHandler implements IViewHandler { 21 | /*============================================================================*/ 22 | /* Private Properties */ 23 | /*============================================================================*/ 24 | 25 | private _mappings: IMediatorMapping[] = []; 26 | 27 | private _knownMappings: Map, IMediatorMapping[] | boolean> = new Map, IMediatorMapping[]>(); 28 | 29 | private _factory: MediatorFactory; 30 | 31 | /*============================================================================*/ 32 | /* Constructor */ 33 | /*============================================================================*/ 34 | 35 | /** 36 | * @private 37 | */ 38 | constructor(factory: MediatorFactory) { 39 | this._factory = factory; 40 | } 41 | 42 | /*============================================================================*/ 43 | /* Public Functions */ 44 | /*============================================================================*/ 45 | 46 | /** 47 | * @private 48 | */ 49 | public addMapping(mapping: IMediatorMapping): void { 50 | let index: number = this._mappings.indexOf(mapping); 51 | if (index > -1) { 52 | return; 53 | } 54 | this._mappings.push(mapping); 55 | this._knownMappings.clear(); 56 | } 57 | 58 | /** 59 | * @private 60 | */ 61 | public removeMapping(mapping: IMediatorMapping): void { 62 | let index: number = this._mappings.indexOf(mapping); 63 | if (index === -1) { 64 | return; 65 | } 66 | this._mappings.splice(index, 1); 67 | this._knownMappings.clear(); 68 | } 69 | 70 | /** 71 | * @private 72 | */ 73 | public handleView(view: DisplayObject, type: IClass): void { 74 | let interestedMappings = this.getInterestedMappingsFor(view, type); 75 | if (interestedMappings) { 76 | this._factory.createMediators(view, type, interestedMappings); 77 | } 78 | } 79 | 80 | /** 81 | * @private 82 | */ 83 | public handleItem(item: any, type: IClass): void { 84 | let interestedMappings = this.getInterestedMappingsFor(item, type); 85 | if (interestedMappings) { 86 | this._factory.createMediators(item, type, interestedMappings); 87 | } 88 | } 89 | 90 | /*============================================================================*/ 91 | /* Private Functions */ 92 | /*============================================================================*/ 93 | 94 | private getInterestedMappingsFor(item: any, type: IClass): IMediatorMapping[] { 95 | // we've seen this type before and nobody was interested 96 | if (this._knownMappings.get(type) === false) { 97 | return null; 98 | } 99 | 100 | // we haven't seen this type before 101 | if (this._knownMappings.get(type) === undefined) { 102 | this._knownMappings.set(type, false); 103 | 104 | this._mappings.forEach((mapping: IMediatorMapping) => { 105 | if (mapping.matcher.matches(item)) { 106 | if (!this._knownMappings.get(type)) { 107 | this._knownMappings.set(type, []); 108 | } 109 | (this._knownMappings.get(type) as IMediatorMapping[]).push(mapping); 110 | } 111 | }); 112 | // nobody cares, let's get out of here 113 | if (this._knownMappings.get(type) === false) { 114 | return null; 115 | } 116 | } 117 | 118 | // these mappings really do care 119 | return this._knownMappings.get(type) as IMediatorMapping[]; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/mediatorMap/impl/NullMediatorUnmapper.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IClass } from "@robotlegsjs/core"; 9 | 10 | import { IMediatorUnmapper } from "../dsl/IMediatorUnmapper"; 11 | 12 | /** 13 | * @private 14 | */ 15 | export class NullMediatorUnmapper implements IMediatorUnmapper { 16 | /*============================================================================*/ 17 | /* Public Functions */ 18 | /*============================================================================*/ 19 | 20 | /** 21 | * @private 22 | */ 23 | public fromMediator(mediatorClass: IClass): void {} 24 | 25 | /** 26 | * @private 27 | */ 28 | public fromAll(): void {} 29 | } 30 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/ManualStageObserverExtension.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IContext, IExtension, IInjector, ILogger } from "@robotlegsjs/core"; 9 | 10 | import { ContainerRegistry } from "./impl/ContainerRegistry"; 11 | import { ManualStageObserver } from "./impl/ManualStageObserver"; 12 | 13 | let installCount: number = 0; 14 | 15 | /** 16 | * This extension install a manual Stage Observer 17 | */ 18 | export class ManualStageObserverExtension implements IExtension { 19 | /*============================================================================*/ 20 | /* Private Static Properties */ 21 | /*============================================================================*/ 22 | 23 | // Really? Yes, there can be only one. 24 | private static _manualStageObserver: ManualStageObserver; 25 | 26 | /*============================================================================*/ 27 | /* Private Properties */ 28 | /*============================================================================*/ 29 | 30 | private _injector: IInjector; 31 | 32 | private _logger: ILogger; 33 | 34 | /*============================================================================*/ 35 | /* Public Functions */ 36 | /*============================================================================*/ 37 | 38 | /** 39 | * @inheritDoc 40 | */ 41 | public extend(context: IContext): void { 42 | context.whenInitializing(this.whenInitializing.bind(this)); 43 | context.whenDestroying(this.whenDestroying.bind(this)); 44 | installCount++; 45 | this._injector = context.injector; 46 | this._logger = context.getLogger(this); 47 | } 48 | 49 | /*============================================================================*/ 50 | /* Private Functions */ 51 | /*============================================================================*/ 52 | 53 | private whenInitializing(): void { 54 | // Hark, an actual Singleton! 55 | if (!ManualStageObserverExtension._manualStageObserver) { 56 | let containerRegistry: ContainerRegistry = this._injector.get(ContainerRegistry); 57 | this._logger.debug("Creating genuine ManualStageObserver Singleton"); 58 | ManualStageObserverExtension._manualStageObserver = new ManualStageObserver(containerRegistry); 59 | } 60 | } 61 | 62 | private whenDestroying(): void { 63 | installCount--; 64 | if (installCount === 0) { 65 | this._logger.debug("Destroying genuine ManualStageObserver Singleton"); 66 | ManualStageObserverExtension._manualStageObserver.destroy(); 67 | ManualStageObserverExtension._manualStageObserver = null; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/StageCrawlerExtension.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container } from "pixi.js"; 9 | 10 | import { IContext, IExtension, IInjector, ILogger } from "@robotlegsjs/core"; 11 | 12 | import { IContextView } from "../contextView/api/IContextView"; 13 | 14 | import { IViewManager } from "./api/IViewManager"; 15 | import { ContainerBinding } from "./impl/ContainerBinding"; 16 | import { ContainerRegistry } from "./impl/ContainerRegistry"; 17 | import { StageCrawler } from "./impl/StageCrawler"; 18 | 19 | /** 20 | * View Handlers (like the MediatorMap) handle views as they land on stage. 21 | * 22 | * This extension checks for views that might already be on the stage 23 | * after context initialization and ensures that those views are handled. 24 | */ 25 | export class StageCrawlerExtension implements IExtension { 26 | /*============================================================================*/ 27 | /* Private Properties */ 28 | /*============================================================================*/ 29 | 30 | private _logger: ILogger; 31 | 32 | private _injector: IInjector; 33 | 34 | private _containerRegistry: ContainerRegistry; 35 | 36 | /*============================================================================*/ 37 | /* Public Functions */ 38 | /*============================================================================*/ 39 | 40 | /** 41 | * @inheritDoc 42 | */ 43 | public extend(context: IContext): void { 44 | this._injector = context.injector; 45 | this._logger = context.getLogger(this); 46 | context.afterInitializing(this.afterInitializing.bind(this)); 47 | } 48 | 49 | /*============================================================================*/ 50 | /* Private Functions */ 51 | /*============================================================================*/ 52 | 53 | private afterInitializing(): void { 54 | this._containerRegistry = this._injector.get(ContainerRegistry); 55 | this._injector.isBound(IViewManager) ? this.scanViewManagedContainers() : this.scanContextView(); 56 | } 57 | 58 | private scanViewManagedContainers(): void { 59 | this._logger.debug("ViewManager is installed. Checking for managed containers..."); 60 | let viewManager: IViewManager = this._injector.get(IViewManager); 61 | viewManager.containers.forEach((container: Container) => { 62 | this.scanContainer(container); 63 | }); 64 | } 65 | 66 | private scanContextView(): void { 67 | if (this._injector.isBound(IContextView)) { 68 | this._logger.debug("ViewManager is not installed. Checking the ContextView..."); 69 | let contextView: IContextView = this._injector.get(IContextView); 70 | this.scanContainer(contextView.view); 71 | } else { 72 | this._logger.error("A ContextView must be installed if you install the StageCrawlerExtension."); 73 | } 74 | } 75 | 76 | private scanContainer(container: Container): void { 77 | let binding: ContainerBinding = this._containerRegistry.getBinding(container); 78 | this._logger.debug("StageCrawler scanning container {0} ...", [container]); 79 | new StageCrawler(binding).scan(container); 80 | this._logger.debug("StageCrawler finished scanning {0}", [container]); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/StageObserverExtension.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IContext, IExtension, IInjector, ILogger } from "@robotlegsjs/core"; 9 | 10 | import { ContainerRegistry } from "./impl/ContainerRegistry"; 11 | import { StageObserver } from "./impl/StageObserver"; 12 | 13 | let installCount: number = 0; 14 | 15 | /** 16 | * This extension install an automatic Stage Observer 17 | */ 18 | export class StageObserverExtension implements IExtension { 19 | /*============================================================================*/ 20 | /* Private Static Properties */ 21 | /*============================================================================*/ 22 | 23 | // Really? Yes, there can be only one. 24 | private static _stageObserver: StageObserver = null; 25 | 26 | /*============================================================================*/ 27 | /* Private Properties */ 28 | /*============================================================================*/ 29 | 30 | private _injector: IInjector; 31 | 32 | private _logger: ILogger; 33 | 34 | /*============================================================================*/ 35 | /* Public Functions */ 36 | /*============================================================================*/ 37 | 38 | /** 39 | * @inheritDoc 40 | */ 41 | public extend(context: IContext): void { 42 | context.whenInitializing(this.whenInitializing.bind(this)); 43 | context.whenDestroying(this.whenDestroying.bind(this)); 44 | installCount++; 45 | this._injector = context.injector; 46 | this._logger = context.getLogger(this); 47 | } 48 | 49 | /*============================================================================*/ 50 | /* Private Functions */ 51 | /*============================================================================*/ 52 | 53 | private whenInitializing(): void { 54 | // Hark, an actual Singleton! 55 | if (!StageObserverExtension._stageObserver) { 56 | let containerRegistry: ContainerRegistry = this._injector.get(ContainerRegistry); 57 | this._logger.debug("Creating genuine StageObserver Singleton"); 58 | StageObserverExtension._stageObserver = new StageObserver(containerRegistry); 59 | } 60 | } 61 | 62 | private whenDestroying(): void { 63 | installCount--; 64 | if (installCount === 0) { 65 | this._logger.debug("Destroying genuine StageObserver Singleton"); 66 | StageObserverExtension._stageObserver.destroy(); 67 | StageObserverExtension._stageObserver = null; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/ViewManagerExtension.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { IContext, IExtension, IInjector } from "@robotlegsjs/core"; 9 | 10 | import { IViewManager } from "../viewManager/api/IViewManager"; 11 | import { ViewManager } from "../viewManager/impl/ViewManager"; 12 | 13 | import { ContainerRegistry } from "./impl/ContainerRegistry"; 14 | 15 | /** 16 | * This extension install a View Manager into the context 17 | */ 18 | export class ViewManagerExtension implements IExtension { 19 | /*============================================================================*/ 20 | /* Private Static Properties */ 21 | /*============================================================================*/ 22 | 23 | // Really? Yes, there can be only one. 24 | private static _containerRegistry: ContainerRegistry; 25 | 26 | /*============================================================================*/ 27 | /* Private Properties */ 28 | /*============================================================================*/ 29 | 30 | private _injector: IInjector; 31 | 32 | private _viewManager: IViewManager; 33 | 34 | /*============================================================================*/ 35 | /* Public Functions */ 36 | /*============================================================================*/ 37 | 38 | /** 39 | * @inheritDoc 40 | */ 41 | public extend(context: IContext): void { 42 | context.whenInitializing(this.whenInitializing.bind(this)); 43 | context.whenDestroying(this.whenDestroying.bind(this)); 44 | 45 | this._injector = context.injector; 46 | 47 | // Just one Container Registry 48 | ViewManagerExtension._containerRegistry = ViewManagerExtension._containerRegistry || new ContainerRegistry(); 49 | this._injector.bind(ContainerRegistry).toConstantValue(ViewManagerExtension._containerRegistry); 50 | 51 | // But you get your own View Manager 52 | this._injector 53 | .bind(IViewManager) 54 | .to(ViewManager) 55 | .inSingletonScope(); 56 | } 57 | 58 | /*============================================================================*/ 59 | /* Private Functions */ 60 | /*============================================================================*/ 61 | 62 | private whenInitializing(): void { 63 | this._viewManager = this._injector.get(IViewManager); 64 | } 65 | 66 | private whenDestroying(): void { 67 | this._viewManager.removeAllHandlers(); 68 | this._injector.unbind(IViewManager); 69 | this._injector.unbind(ContainerRegistry); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/api/IViewHandler.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { DisplayObject } from "pixi.js"; 9 | 10 | import { IClass } from "@robotlegsjs/core"; 11 | 12 | /** 13 | * View handler contract 14 | */ 15 | export interface IViewHandler { 16 | /** 17 | * View handler method 18 | * @param view The view instance to handle 19 | * @param type The class of the view instance 20 | */ 21 | handleView(view: DisplayObject, type: IClass): void; 22 | } 23 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/api/IViewManager.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container } from "pixi.js"; 9 | 10 | import { IEventDispatcher } from "@robotlegsjs/core"; 11 | import { IViewHandler } from "./IViewHandler"; 12 | 13 | /*[Event(name="containerAdd", type="robotlegs.bender.extensions.viewManager.impl.ViewManagerEvent")]*/ 14 | /*[Event(name="containerRemove", type="robotlegs.bender.extensions.viewManager.impl.ViewManagerEvent")]*/ 15 | /*[Event(name="handlerAdd", type="robotlegs.bender.extensions.viewManager.impl.ViewManagerEvent")]*/ 16 | /*[Event(name="handlerRemove", type="robotlegs.bender.extensions.viewManager.impl.ViewManagerEvent")]*/ 17 | 18 | /** 19 | * The View Manager allows you to add multiple "view root" containers to a context 20 | */ 21 | export let IViewManager = Symbol("IViewManager"); 22 | export interface IViewManager extends IEventDispatcher { 23 | /** 24 | * A list of currently registered containers 25 | */ 26 | containers: Container[]; 27 | 28 | /** 29 | * Adds a container as a "view root" into the context 30 | * @param container 31 | */ 32 | addContainer(container: Container): void; 33 | 34 | /** 35 | * Removes a container from this context 36 | * @param container 37 | */ 38 | removeContainer(container: Container): void; 39 | 40 | /** 41 | * Registers a view handler 42 | * @param handler 43 | */ 44 | addViewHandler(handler: IViewHandler): void; 45 | 46 | /** 47 | * Removes a view handler 48 | * @param handler 49 | */ 50 | removeViewHandler(handler: IViewHandler): void; 51 | 52 | /** 53 | * Removes all view handlers from this context 54 | */ 55 | removeAllHandlers(): void; 56 | } 57 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/impl/ConfigureViewEvent.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Event } from "@robotlegsjs/core"; 9 | 10 | import { Container } from "pixi.js"; 11 | 12 | /** 13 | * View Configuration Event 14 | * @private 15 | */ 16 | export class ConfigureViewEvent extends Event { 17 | /*============================================================================*/ 18 | /* Public Static Properties */ 19 | /*============================================================================*/ 20 | 21 | public static CONFIGURE_VIEW: string = "configureView"; 22 | 23 | /*============================================================================*/ 24 | /* Public Properties */ 25 | /*============================================================================*/ 26 | 27 | private _view: Container; 28 | 29 | /** 30 | * The view instance associated with this event 31 | */ 32 | public get view(): Container { 33 | return this._view; 34 | } 35 | 36 | /*============================================================================*/ 37 | /* Constructor */ 38 | /*============================================================================*/ 39 | 40 | /** 41 | * Creates a view configuration event 42 | * @param type The event type 43 | * @param view The associated view instance 44 | */ 45 | constructor(type: string, view: Container) { 46 | super(type, true); 47 | this._view = view; 48 | } 49 | 50 | /*============================================================================*/ 51 | /* Public Functions */ 52 | /*============================================================================*/ 53 | 54 | /** 55 | * @inheritDoc 56 | */ 57 | public clone(): ConfigureViewEvent { 58 | return new ConfigureViewEvent(this.type, this._view); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/impl/ContainerBinding.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container, DisplayObject } from "pixi.js"; 9 | 10 | import { IClass, EventDispatcher } from "@robotlegsjs/core"; 11 | 12 | import { IViewHandler } from "../api/IViewHandler"; 13 | 14 | import { ContainerBindingEvent } from "./ContainerBindingEvent"; 15 | 16 | /*[Event(name="bindingEmpty", type="robotlegs.bender.extensions.viewManager.impl.ContainerBindingEvent")]*/ 17 | /** 18 | * @private 19 | */ 20 | export class ContainerBinding extends EventDispatcher { 21 | /*============================================================================*/ 22 | /* Public Properties */ 23 | /*============================================================================*/ 24 | 25 | private _parent: ContainerBinding; 26 | 27 | /** 28 | * @private 29 | */ 30 | public get parent(): ContainerBinding { 31 | return this._parent; 32 | } 33 | 34 | /** 35 | * @private 36 | */ 37 | public set parent(value: ContainerBinding) { 38 | this._parent = value; 39 | } 40 | 41 | private _container: Container; 42 | 43 | /** 44 | * @private 45 | */ 46 | public get container(): Container { 47 | return this._container; 48 | } 49 | 50 | /*============================================================================*/ 51 | /* Private Properties */ 52 | /*============================================================================*/ 53 | 54 | private _handlers: IViewHandler[] = []; 55 | 56 | /*============================================================================*/ 57 | /* Constructor */ 58 | /*============================================================================*/ 59 | 60 | /** 61 | * @private 62 | */ 63 | constructor(container: Container) { 64 | super(); 65 | this._container = container; 66 | } 67 | 68 | /*============================================================================*/ 69 | /* Public Functions */ 70 | /*============================================================================*/ 71 | 72 | /** 73 | * @private 74 | */ 75 | public addHandler(handler: IViewHandler): void { 76 | if (this._handlers.indexOf(handler) > -1) { 77 | return; 78 | } 79 | this._handlers.push(handler); 80 | } 81 | 82 | /** 83 | * @private 84 | */ 85 | public removeHandler(handler: IViewHandler): void { 86 | let index: number = this._handlers.indexOf(handler); 87 | if (index > -1) { 88 | this._handlers.splice(index, 1); 89 | if (this._handlers.length === 0) { 90 | this.dispatchEvent(new ContainerBindingEvent(ContainerBindingEvent.BINDING_EMPTY)); 91 | } 92 | } 93 | } 94 | 95 | /** 96 | * @private 97 | */ 98 | public handleView(view: DisplayObject, type: IClass): void { 99 | let length: number = this._handlers.length; 100 | for (let i: number = 0; i < length; i++) { 101 | let handler: IViewHandler = this._handlers[i]; 102 | handler.handleView(view, type); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/impl/ContainerBindingEvent.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Event } from "@robotlegsjs/core"; 9 | 10 | /** 11 | * @private 12 | */ 13 | export class ContainerBindingEvent extends Event { 14 | /*============================================================================*/ 15 | /* Public Static Properties */ 16 | /*============================================================================*/ 17 | 18 | public static BINDING_EMPTY: string = "bindingEmpty"; 19 | 20 | /*============================================================================*/ 21 | /* Constructor */ 22 | /*============================================================================*/ 23 | 24 | /** 25 | * @private 26 | */ 27 | constructor(type: string) { 28 | super(type); 29 | } 30 | 31 | /*============================================================================*/ 32 | /* Public Functions */ 33 | /*============================================================================*/ 34 | 35 | /** 36 | * @inheritDoc 37 | */ 38 | public clone(): ContainerBindingEvent { 39 | return new ContainerBindingEvent(this.type); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistryEvent.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container } from "pixi.js"; 9 | 10 | import { Event } from "@robotlegsjs/core"; 11 | 12 | /** 13 | * Container existence event 14 | * @private 15 | */ 16 | export class ContainerRegistryEvent extends Event { 17 | /*============================================================================*/ 18 | /* Public Static Properties */ 19 | /*============================================================================*/ 20 | 21 | public static CONTAINER_ADD: string = "containerAdd"; 22 | 23 | public static CONTAINER_REMOVE: string = "containerRemove"; 24 | 25 | public static ROOT_CONTAINER_ADD: string = "rootContainerAdd"; 26 | 27 | public static ROOT_CONTAINER_REMOVE: string = "rootContainerRemove"; 28 | 29 | /*============================================================================*/ 30 | /* Public Properties */ 31 | /*============================================================================*/ 32 | 33 | private _container: Container; 34 | 35 | /** 36 | * The container associated with this event 37 | */ 38 | public get container(): Container { 39 | return this._container; 40 | } 41 | 42 | /*============================================================================*/ 43 | /* Constructor */ 44 | /*============================================================================*/ 45 | 46 | /** 47 | * Creates a new container existence event 48 | * @param type The event type 49 | * @param container The container associated with this event 50 | */ 51 | constructor(type: string, container: Container) { 52 | super(type); 53 | this._container = container; 54 | } 55 | 56 | /*============================================================================*/ 57 | /* Public Functions */ 58 | /*============================================================================*/ 59 | 60 | /** 61 | * @inheritDoc 62 | */ 63 | public clone(): ContainerRegistryEvent { 64 | return new ContainerRegistryEvent(this.type, this._container); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/impl/ManualStageObserver.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container, DisplayObject } from "pixi.js"; 9 | 10 | import { IClass } from "@robotlegsjs/core"; 11 | 12 | import { ContainerRegistryEvent } from "./ContainerRegistryEvent"; 13 | 14 | import { ContainerRegistry } from "./ContainerRegistry"; 15 | import { ContainerBinding } from "./ContainerBinding"; 16 | 17 | import { ConfigureViewEvent } from "./ConfigureViewEvent"; 18 | 19 | /** 20 | * @private 21 | */ 22 | export class ManualStageObserver { 23 | /*============================================================================*/ 24 | /* Private Properties */ 25 | /*============================================================================*/ 26 | 27 | private _registry: ContainerRegistry; 28 | 29 | /*============================================================================*/ 30 | /* Constructor */ 31 | /*============================================================================*/ 32 | 33 | /** 34 | * @private 35 | */ 36 | constructor(containerRegistry: ContainerRegistry) { 37 | this._registry = containerRegistry; 38 | 39 | // We care about all containers (not just roots) 40 | this._registry.addEventListener(ContainerRegistryEvent.CONTAINER_ADD, this.onContainerAdd, this); 41 | this._registry.addEventListener(ContainerRegistryEvent.CONTAINER_REMOVE, this.onContainerRemove, this); 42 | 43 | // We might have arrived late on the scene 44 | this._registry.bindings.forEach((binding: ContainerBinding) => { 45 | this.addContainerListener(binding.container); 46 | }); 47 | } 48 | 49 | /*============================================================================*/ 50 | /* Public Functions */ 51 | /*============================================================================*/ 52 | 53 | /** 54 | * @private 55 | */ 56 | public destroy(): void { 57 | this._registry.removeEventListener(ContainerRegistryEvent.CONTAINER_ADD, this.onContainerAdd, this); 58 | this._registry.removeEventListener(ContainerRegistryEvent.CONTAINER_REMOVE, this.onContainerRemove, this); 59 | 60 | this._registry.rootBindings.forEach((binding: ContainerBinding) => { 61 | this.removeContainerListener(binding.container); 62 | }); 63 | } 64 | 65 | /*============================================================================*/ 66 | /* Private Functions */ 67 | /*============================================================================*/ 68 | 69 | private onContainerAdd(event: ContainerRegistryEvent): void { 70 | this.addContainerListener(event.container); 71 | } 72 | 73 | private onContainerRemove(event: ContainerRegistryEvent): void { 74 | this.removeContainerListener(event.container); 75 | } 76 | 77 | private addContainerListener(container: Container): void { 78 | // We're interested in ALL container bindings 79 | // but just for normal, bubbling events 80 | container.addEventListener(ConfigureViewEvent.CONFIGURE_VIEW, this.onConfigureView, this); 81 | } 82 | 83 | private removeContainerListener(container: Container): void { 84 | container.removeEventListener(ConfigureViewEvent.CONFIGURE_VIEW, this.onConfigureView, this); 85 | } 86 | 87 | private onConfigureView(event: ConfigureViewEvent): void { 88 | // Stop that event! 89 | event.stopPropagation(); 90 | 91 | let container: Container = event.currentTarget; 92 | let view: DisplayObject = event.target; 93 | let type: IClass = >view.constructor; 94 | this._registry.getBinding(container).handleView(view, type); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/impl/StageCrawler.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container, DisplayObject } from "pixi.js"; 9 | 10 | import { IClass } from "@robotlegsjs/core"; 11 | 12 | import { ContainerBinding } from "./ContainerBinding"; 13 | 14 | /** 15 | * @private 16 | */ 17 | export class StageCrawler { 18 | /*============================================================================*/ 19 | /* Private Properties */ 20 | /*============================================================================*/ 21 | 22 | private _binding: ContainerBinding; 23 | 24 | /*============================================================================*/ 25 | /* Constructor */ 26 | /*============================================================================*/ 27 | 28 | /** 29 | * @private 30 | */ 31 | constructor(containerBinding: ContainerBinding) { 32 | this._binding = containerBinding; 33 | } 34 | 35 | /*============================================================================*/ 36 | /* Public Functions */ 37 | /*============================================================================*/ 38 | 39 | /** 40 | * @private 41 | */ 42 | public scan(container: Container): void { 43 | this.scanContainer(container); 44 | } 45 | 46 | /*============================================================================*/ 47 | /* Private Functions */ 48 | /*============================================================================*/ 49 | 50 | private scanContainer(container: Container): void { 51 | this.processView(container); 52 | 53 | container.children.forEach(child => { 54 | if (child instanceof Container) { 55 | this.scanContainer(child); 56 | } else { 57 | this.processView(child); 58 | } 59 | }); 60 | } 61 | 62 | private processView(view: DisplayObject): void { 63 | this._binding.handleView(view, >view.constructor); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/impl/StageObserver.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container } from "pixi.js"; 9 | 10 | import { IClass, IEvent } from "@robotlegsjs/core"; 11 | 12 | import { ContainerBinding } from "./ContainerBinding"; 13 | import { ContainerRegistry } from "./ContainerRegistry"; 14 | import { ContainerRegistryEvent } from "./ContainerRegistryEvent"; 15 | 16 | /** 17 | * @private 18 | */ 19 | export class StageObserver { 20 | /*============================================================================*/ 21 | /* Private Properties */ 22 | /*============================================================================*/ 23 | 24 | private _registry: ContainerRegistry; 25 | 26 | /*============================================================================*/ 27 | /* Constructor */ 28 | /*============================================================================*/ 29 | 30 | /** 31 | * @private 32 | */ 33 | constructor(containerRegistry: ContainerRegistry) { 34 | this._registry = containerRegistry; 35 | 36 | // We only care about roots 37 | this._registry.addEventListener(ContainerRegistryEvent.ROOT_CONTAINER_ADD, this.onRootContainerAdd, this); 38 | this._registry.addEventListener(ContainerRegistryEvent.ROOT_CONTAINER_REMOVE, this.onRootContainerRemove, this); 39 | 40 | // We might have arrived late on the scene 41 | this._registry.rootBindings.forEach((binding: ContainerBinding) => { 42 | this.addRootListener(binding.container); 43 | }); 44 | } 45 | 46 | /*============================================================================*/ 47 | /* Public Functions */ 48 | /*============================================================================*/ 49 | 50 | /** 51 | * @private 52 | */ 53 | public destroy(): void { 54 | this._registry.removeEventListener(ContainerRegistryEvent.ROOT_CONTAINER_ADD, this.onRootContainerAdd, this); 55 | this._registry.removeEventListener(ContainerRegistryEvent.ROOT_CONTAINER_REMOVE, this.onRootContainerRemove, this); 56 | 57 | this._registry.rootBindings.forEach((binding: ContainerBinding) => { 58 | this.removeRootListener(binding.container); 59 | }); 60 | } 61 | 62 | /*============================================================================*/ 63 | /* Private Functions */ 64 | /*============================================================================*/ 65 | 66 | private onRootContainerAdd(event: ContainerRegistryEvent): void { 67 | this.addRootListener(event.container); 68 | } 69 | 70 | private onRootContainerRemove(event: ContainerRegistryEvent): void { 71 | this.removeRootListener(event.container); 72 | } 73 | 74 | private addRootListener(container: Container): void { 75 | container.addEventListener("added", this.onViewAddedToStage, this); 76 | } 77 | 78 | private removeRootListener(container: Container): void { 79 | container.removeEventListener("added", this.onViewAddedToStage, this); 80 | } 81 | 82 | private onViewAddedToStage(event: IEvent): void { 83 | let view: Container = event.target; 84 | let type: IClass = >view.constructor; 85 | 86 | // Walk upwards from the nearest binding 87 | let binding: ContainerBinding = this._registry.findParentBinding(view); 88 | while (binding) { 89 | binding.handleView(view, type); 90 | binding = binding.parent; 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/robotlegs/bender/extensions/viewManager/impl/ViewManagerEvent.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container } from "pixi.js"; 9 | 10 | import { Event } from "@robotlegsjs/core"; 11 | 12 | import { IViewHandler } from "../api/IViewHandler"; 13 | 14 | /** 15 | * Container existence event 16 | * @private 17 | */ 18 | export class ViewManagerEvent extends Event { 19 | /*============================================================================*/ 20 | /* Public Static Properties */ 21 | /*============================================================================*/ 22 | 23 | public static CONTAINER_ADD: string = "containerAdd"; 24 | 25 | public static CONTAINER_REMOVE: string = "containerRemove"; 26 | 27 | public static HANDLER_ADD: string = "handlerAdd"; 28 | 29 | public static HANDLER_REMOVE: string = "handlerRemove"; 30 | 31 | /*============================================================================*/ 32 | /* Public Properties */ 33 | /*============================================================================*/ 34 | 35 | private _container: Container; 36 | 37 | /** 38 | * The container associated with this event 39 | */ 40 | public get container(): Container { 41 | return this._container; 42 | } 43 | 44 | private _handler: IViewHandler; 45 | 46 | /** 47 | * The view handler associated with this event 48 | */ 49 | public get handler(): IViewHandler { 50 | return this._handler; 51 | } 52 | 53 | /*============================================================================*/ 54 | /* Constructor */ 55 | /*============================================================================*/ 56 | 57 | /** 58 | * Creates a view manager event 59 | * @param type The event type 60 | * @param container The container associated with this event 61 | * @param handler The view handler associated with this event 62 | */ 63 | constructor(type: string, container?: Container, handler?: IViewHandler) { 64 | super(type); 65 | this._container = container; 66 | this._handler = handler; 67 | } 68 | 69 | /*============================================================================*/ 70 | /* Public Functions */ 71 | /*============================================================================*/ 72 | 73 | /** 74 | * @inheritDoc 75 | */ 76 | public clone(): ViewManagerEvent { 77 | return new ViewManagerEvent(this.type, this._container, this._handler); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /static/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotlegsJS/RobotlegsJS-Pixi/0606cc590c151d0c67527277ff0d53f481de9289/static/images/loading.gif -------------------------------------------------------------------------------- /static/images/pixijs-v5-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotlegsJS/RobotlegsJS-Pixi/0606cc590c151d0c67527277ff0d53f481de9289/static/images/pixijs-v5-logo.png -------------------------------------------------------------------------------- /static/images/robotlegs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RobotlegsJS/RobotlegsJS-Pixi/0606cc590c151d0c67527277ff0d53f481de9289/static/images/robotlegs.png -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RobotlegsJS PixiJS Boilerplate 6 | 7 | 8 | 9 | 10 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |

integration with PixiJS

29 |

30 | This example shows how to integrate RobotlegsJS framework with PixiJS. Click on the logo to see 31 | some action! 32 |

33 |
34 | 35 | 36 | 37 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Your Game", 3 | "short_name": "Your Game", 4 | "start_url": "index.html", 5 | "display": "standalone", 6 | "orientation": "landscape", 7 | "icons": [ 8 | { 9 | "src": "icon.png", 10 | "sizes": "512x512", 11 | "type": "image/png" 12 | }, 13 | { 14 | "src": "launcher-icon-2x.png", 15 | "sizes": "96x96", 16 | "type": "image/png" 17 | }, 18 | { 19 | "src": "launcher-icon-3x.png", 20 | "sizes": "144x144", 21 | "type": "image/png" 22 | }, 23 | { 24 | "src": "launcher-icon-4x.png", 25 | "sizes": "192x192", 26 | "type": "image/png" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /static/scripts/cache-polyfill.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 Google Inc. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | (function() { 19 | var nativeAddAll = Cache.prototype.addAll; 20 | var userAgent = navigator.userAgent.match(/(Firefox|Chrome)\/(\d+\.)/); 21 | 22 | // Has nice behavior of `var` which everyone hates 23 | if (userAgent) { 24 | var agent = userAgent[1]; 25 | var version = parseInt(userAgent[2]); 26 | } 27 | 28 | if (nativeAddAll && (!userAgent || (agent === "Firefox" && version >= 46) || (agent === "Chrome" && version >= 50))) { 29 | return; 30 | } 31 | 32 | Cache.prototype.addAll = function addAll(requests) { 33 | var cache = this; 34 | 35 | // Since DOMExceptions are not constructable: 36 | function NetworkError(message) { 37 | this.name = "NetworkError"; 38 | this.code = 19; 39 | this.message = message; 40 | } 41 | 42 | NetworkError.prototype = Object.create(Error.prototype); 43 | 44 | return Promise.resolve() 45 | .then(function() { 46 | if (arguments.length < 1) throw new TypeError(); 47 | 48 | // Simulate sequence<(Request or USVString)> binding: 49 | var sequence = []; 50 | 51 | requests = requests.map(function(request) { 52 | if (request instanceof Request) { 53 | return request; 54 | } else { 55 | return String(request); // may throw TypeError 56 | } 57 | }); 58 | 59 | return Promise.all( 60 | requests.map(function(request) { 61 | if (typeof request === "string") { 62 | request = new Request(request); 63 | } 64 | 65 | var scheme = new URL(request.url).protocol; 66 | 67 | if (scheme !== "http:" && scheme !== "https:") { 68 | throw new NetworkError("Invalid scheme"); 69 | } 70 | 71 | return fetch(request.clone()); 72 | }) 73 | ); 74 | }) 75 | .then(function(responses) { 76 | // If some of the responses has not OK-eish status, 77 | // then whole operation should reject 78 | if ( 79 | responses.some(function(response) { 80 | return !response.ok; 81 | }) 82 | ) { 83 | throw new NetworkError("Incorrect response status"); 84 | } 85 | 86 | // TODO: check that requests don't overwrite one another 87 | // (don't think this is possible to polyfill due to opaque responses) 88 | return Promise.all( 89 | responses.map(function(response, i) { 90 | return cache.put(requests[i], response); 91 | }) 92 | ); 93 | }) 94 | .then(function() { 95 | return undefined; 96 | }); 97 | }; 98 | 99 | Cache.prototype.add = function add(request) { 100 | return this.addAll([request]); 101 | }; 102 | })(); 103 | -------------------------------------------------------------------------------- /static/service-worker.js: -------------------------------------------------------------------------------- 1 | importScripts("scripts/cache-polyfill.js"); 2 | 3 | var CACHE_VERSION = "app-v1"; 4 | var CACHE_FILES = ["index.html"]; 5 | 6 | self.addEventListener("install", function(event) { 7 | event.waitUntil( 8 | caches.open(CACHE_VERSION).then(function(cache) { 9 | console.log("Opened cache"); 10 | return cache.addAll(CACHE_FILES); 11 | }) 12 | ); 13 | }); 14 | 15 | self.addEventListener("activate", function(event) { 16 | event.waitUntil( 17 | caches.keys().then(function(keys) { 18 | return Promise.all( 19 | keys.map(function(key, i) { 20 | if (key !== CACHE_VERSION) { 21 | return caches.delete(keys[i]); 22 | } 23 | }) 24 | ); 25 | }) 26 | ); 27 | }); 28 | 29 | self.addEventListener("fetch", function(event) { 30 | event.respondWith( 31 | caches.match(event.request).then(function(res) { 32 | if (res) { 33 | return res; 34 | } 35 | requestBackend(event); 36 | }) 37 | ); 38 | }); 39 | 40 | function requestBackend(event) { 41 | var url = event.request.clone(); 42 | return fetch(url).then(function(res) { 43 | //if not a valid response send the error 44 | if (!res || res.status !== 200 || res.type !== "basic") { 45 | return res; 46 | } 47 | 48 | var response = res.clone(); 49 | 50 | caches.open(CACHE_VERSION).then(function(cache) { 51 | cache.put(event.request, response); 52 | }); 53 | 54 | return res; 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /static/styles/example.css: -------------------------------------------------------------------------------- 1 | body { 2 | width: 960px; 3 | } 4 | 5 | header { 6 | margin-bottom: 1rem; 7 | } 8 | 9 | h1 { 10 | font-weight: 200; 11 | margin-bottom: 1rem; 12 | } 13 | 14 | h1:before { 15 | content: "RobotlegsJS "; 16 | font-weight: bold; 17 | } 18 | 19 | header p { 20 | margin: 0; 21 | padding: 1em; 22 | background: rgba(250, 252, 255, 0.7); 23 | } 24 | 25 | .content, 26 | canvas { 27 | background: white; 28 | } 29 | 30 | .content { 31 | width: 960px; 32 | height: 400px; 33 | overflow: hidden; 34 | } 35 | 36 | .loading { 37 | position: relative; 38 | } 39 | 40 | .loading:after { 41 | content: url("../images/loading.gif"); 42 | position: absolute; 43 | left: 50%; 44 | top: 50%; 45 | margin: -13px 0 0 -51px; 46 | opacity: 0.8; 47 | } 48 | 49 | #error { 50 | display: none; 51 | width: 960px; 52 | text-align: left; 53 | padding: 10px; 54 | } 55 | 56 | #mobile { 57 | display: none; 58 | width: 960px; 59 | text-align: left; 60 | padding: 10px; 61 | } 62 | 63 | body.embedded header { 64 | display: none; 65 | } 66 | 67 | body.embedded { 68 | margin: 0; 69 | } 70 | -------------------------------------------------------------------------------- /static/styles/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 3em auto; 3 | padding: 0; 4 | background-color: #eaebee; 5 | font-family: Arial, Verdana, sans-serif; 6 | font-size: 14px; 7 | font-weight: normal; 8 | color: #333; 9 | line-height: 1.4em; 10 | } 11 | 12 | a:link, 13 | a:visited { 14 | color: #39f; 15 | text-decoration: none; 16 | } 17 | 18 | a:hover { 19 | text-decoration: underline; 20 | } 21 | 22 | h1, 23 | h2 { 24 | color: #fff; 25 | font-size: 1.6em; 26 | margin-bottom: 0; 27 | padding: 1.5em; 28 | padding-bottom: 1.2em; 29 | background: #374252; 30 | } 31 | 32 | h1::after { 33 | display: block; 34 | content: ""; 35 | background: url("../images/pixijs-v5-logo.png") no-repeat; 36 | height: 33px; 37 | width: 110px; 38 | margin-top: -0.3em; 39 | float: right; 40 | } 41 | 42 | h1 em { 43 | font-weight: 200; 44 | font-style: normal; 45 | } 46 | 47 | h2 { 48 | font-size: 1.3em; 49 | padding: 1em; 50 | padding-bottom: 0.8em; 51 | } 52 | 53 | h3 { 54 | background: #e0e1e5; 55 | color: #374252; 56 | font-size: 1.25em; 57 | padding: 0.5em; 58 | margin-top: 1.25em; 59 | margin-bottom: -0.5em; 60 | position: relative; 61 | } 62 | 63 | code { 64 | color: black; 65 | background-color: rgba(255, 230, 0, 0.33); 66 | padding: 1px 3px; 67 | font-family: Courier New, Courier, serif; 68 | font-weight: bold; 69 | } 70 | 71 | /** 72 | * For modern browsers 73 | * 1. The space content is one way to avoid an Opera bug when the 74 | * contenteditable attribute is included anywhere else in the document. 75 | * Otherwise it causes space to appear at the top and bottom of elements 76 | * that are clearfixed. 77 | * 2. The use of `table` rather than `block` is only necessary if using 78 | * `:before` to contain the top-margins of child elements. 79 | */ 80 | .cf:before, 81 | .cf:after { 82 | content: " "; /* 1 */ 83 | display: table; /* 2 */ 84 | } 85 | 86 | .cf:after { 87 | clear: both; 88 | } 89 | 90 | /** 91 | * For IE 6/7 only 92 | * Include this rule to trigger hasLayout and contain floats. 93 | */ 94 | .cf { 95 | *zoom: 1; 96 | } 97 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Robotlegs Testing 2 | 3 | Unit tests are written using Mocha, Chai and Sinon. -------------------------------------------------------------------------------- /test/entry.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | /// 9 | /// 10 | 11 | import "reflect-metadata"; 12 | import "bluebird/js/browser/bluebird"; 13 | import "es6-symbol/implement"; 14 | import "es6-map/implement"; 15 | -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // require all modules ending in ".test.ts" from the 4 | // current directory and all subdirectories 5 | const testsContext = require.context(".", true, /\.test\.ts$/); 6 | 7 | testsContext.keys().forEach(testsContext); 8 | -------------------------------------------------------------------------------- /test/robotlegs/bender/bundles/pixi/pixiBundle.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Container } from "pixi.js"; 13 | 14 | import { IContext, Context, LogLevel } from "@robotlegsjs/core"; 15 | 16 | import { IContextView, IMediatorMap, IViewManager, ContextView, PixiBundle } from "../../../../../src"; 17 | 18 | import { ContainerRegistry } from "../../../../../src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistry"; 19 | 20 | import { CallbackLogTarget } from "../../extensions/contextView/support/CallbackLogTarget"; 21 | import { LogParams } from "../../extensions/contextView/support/LogParams"; 22 | 23 | describe("PixiBundle", () => { 24 | let context: IContext; 25 | 26 | afterEach(() => { 27 | if (context.initialized) { 28 | context.destroy(); 29 | } 30 | context = null; 31 | }); 32 | 33 | it("bundle_is_properly_installed_into_context", () => { 34 | context = new Context(); 35 | context 36 | .install(PixiBundle) 37 | .configure(new ContextView(new Container())) 38 | .initialize(); 39 | 40 | // Verify if all extensions are installed 41 | assert.isTrue(context.injector.isBound(IContextView)); 42 | assert.isTrue(context.injector.isBound(ContainerRegistry)); 43 | assert.isTrue(context.injector.isBound(IViewManager)); 44 | assert.isTrue(context.injector.isBound(IMediatorMap)); 45 | }); 46 | 47 | it("bundle_logs_an_error_message_when_context_view_is_not_provided", () => { 48 | let errorLogged: boolean = false; 49 | let logTarget: CallbackLogTarget = new CallbackLogTarget((log: LogParams) => { 50 | if (log.source instanceof PixiBundle && log.level === LogLevel.ERROR) { 51 | errorLogged = log.message === "PixiBundle requires IContextView."; 52 | } 53 | }); 54 | 55 | context = new Context(); 56 | context.addLogTarget(logTarget); 57 | context.install(PixiBundle).initialize(); 58 | assert.isTrue(errorLogged); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/contextView/contextViewExtension.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Container } from "pixi.js"; 13 | 14 | import { IContext, Context, LogLevel } from "@robotlegsjs/core"; 15 | 16 | import { IContextView, ContextView, ContextViewExtension } from "../../../../../src"; 17 | 18 | import { CallbackLogTarget } from "./support/CallbackLogTarget"; 19 | import { LogParams } from "./support/LogParams"; 20 | 21 | describe("ContextViewExtension", () => { 22 | let context: IContext; 23 | 24 | beforeEach(() => { 25 | context = new Context(); 26 | }); 27 | 28 | afterEach(() => { 29 | context.destroy(); 30 | context = null; 31 | }); 32 | 33 | it("installing_after_initialization_throws_error", () => { 34 | function installExtensionAfterInitialization(): void { 35 | context.initialize(); 36 | context.install(ContextViewExtension); 37 | } 38 | assert.throws(installExtensionAfterInitialization, Error); 39 | }); 40 | 41 | it("contextView_is_mapped", () => { 42 | let container = new Container(); 43 | let actual: ContextView = null; 44 | context.install(ContextViewExtension).configure(new ContextView(container)); 45 | context.whenInitializing(function(): void { 46 | actual = context.injector.get(IContextView); 47 | }); 48 | context.initialize(); 49 | assert.equal(actual.view, container); 50 | }); 51 | 52 | it("second_displayObjectContainer_is_ignored", () => { 53 | let container = new Container(); 54 | let actual: ContextView = null; 55 | let secondContainer = new Container(); 56 | context.install(ContextViewExtension).configure(new ContextView(container), new ContextView(secondContainer)); 57 | context.whenInitializing(function(): void { 58 | actual = context.injector.get(IContextView); 59 | }); 60 | context.initialize(); 61 | assert.equal(actual.view, container); 62 | }); 63 | 64 | it("extension_logs_error_when_context_initialized_with_no_contextView", () => { 65 | let errorLogged: boolean = false; 66 | let logTarget: CallbackLogTarget = new CallbackLogTarget(function(log: LogParams): void { 67 | if (log.source instanceof ContextViewExtension && log.level === LogLevel.ERROR) { 68 | errorLogged = true; 69 | } 70 | }); 71 | context.install(ContextViewExtension); 72 | context.addLogTarget(logTarget); 73 | context.initialize(); 74 | assert.isTrue(errorLogged); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/contextView/impl/contextView.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Container } from "pixi.js"; 13 | 14 | import { IContextView, ContextView } from "../../../../../../src"; 15 | 16 | describe("ContextView", () => { 17 | let container: Container; 18 | let contextView: IContextView; 19 | 20 | beforeEach(() => { 21 | container = new Container(); 22 | contextView = new ContextView(container); 23 | }); 24 | 25 | afterEach(() => { 26 | contextView = null; 27 | container = null; 28 | }); 29 | 30 | it("container_is_stored", () => { 31 | assert.isNotNull(contextView.view); 32 | assert.equal(contextView.view, container); 33 | }); 34 | 35 | it("ContextView_throws_a_error_when_view_is_null", () => { 36 | function inicializeContextViewWithNullView(): void { 37 | contextView = new ContextView(null); 38 | } 39 | assert.throws(inicializeContextViewWithNullView, Error); 40 | }); 41 | 42 | it("ContextView_throws_a_error_when_view_is_undefined", () => { 43 | function inicializeContextViewWithUndefinedView(): void { 44 | contextView = new ContextView(undefined); 45 | } 46 | assert.throws(inicializeContextViewWithUndefinedView, Error); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/contextView/impl/contextViewListenerConfig.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Container } from "pixi.js"; 13 | 14 | import { IContextView, ContextView, ContextViewListenerConfig } from "../../../../../../src"; 15 | 16 | import { ContainerRegistry } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistry"; 17 | import { ViewManager } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ViewManager"; 18 | 19 | describe("ContextViewListenerConfig", () => { 20 | let container: Container; 21 | let contextView: IContextView; 22 | let containerRegistry: ContainerRegistry; 23 | let viewManager: ViewManager; 24 | let contextViewListenerConfig: ContextViewListenerConfig; 25 | 26 | beforeEach(() => { 27 | container = new Container(); 28 | contextView = new ContextView(container); 29 | containerRegistry = new ContainerRegistry(); 30 | viewManager = new ViewManager(containerRegistry); 31 | contextViewListenerConfig = new ContextViewListenerConfig(contextView, viewManager); 32 | }); 33 | 34 | afterEach(() => { 35 | contextView = null; 36 | container = null; 37 | containerRegistry = null; 38 | viewManager = null; 39 | contextViewListenerConfig = null; 40 | }); 41 | 42 | it("container_is_added_to_view_manager", () => { 43 | contextViewListenerConfig.configure(); 44 | assert.deepEqual(viewManager.containers, [container]); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/contextView/pixiPatch/containsPatch.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Container, DisplayObject } from "pixi.js"; 13 | 14 | import "../../../../../../src/robotlegs/bender/extensions/contextView/pixiPatch/pixi-patch"; 15 | 16 | describe("ContainsPatch", () => { 17 | let container: Container; 18 | 19 | beforeEach(() => { 20 | container = new Container(); 21 | }); 22 | 23 | afterEach(() => { 24 | container.removeChildren(); 25 | container = null; 26 | }); 27 | 28 | it("Container_have_contains_method", () => { 29 | assert.isNotNull(container.contains); 30 | assert.isFunction(container.contains); 31 | }); 32 | 33 | it("Container_contains_itself", () => { 34 | assert.isTrue(container.contains(container)); 35 | }); 36 | 37 | it("Container_contains_direct_child", () => { 38 | let child: DisplayObject = new DisplayObject(); 39 | 40 | container.addChild(child); 41 | 42 | assert.isTrue(container.contains(child)); 43 | }); 44 | 45 | it("Container_contains_direct_children", () => { 46 | let child1: DisplayObject = new DisplayObject(); 47 | let child2: DisplayObject = new DisplayObject(); 48 | let child3: DisplayObject = new DisplayObject(); 49 | 50 | container.addChild(child1); 51 | container.addChild(child2); 52 | container.addChild(child3); 53 | 54 | assert.isTrue(container.contains(child1)); 55 | assert.isTrue(container.contains(child2)); 56 | assert.isTrue(container.contains(child3)); 57 | }); 58 | 59 | it("Container_contains_nested_children", () => { 60 | let child1: Container = new Container(); 61 | let child2: DisplayObject = new DisplayObject(); 62 | let child3: DisplayObject = new DisplayObject(); 63 | let grandChild1: Container = new Container(); 64 | let grandChild2: DisplayObject = new DisplayObject(); 65 | let grandChild3: DisplayObject = new DisplayObject(); 66 | let greatGrandChild1: DisplayObject = new DisplayObject(); 67 | let greatGrandChild2: DisplayObject = new DisplayObject(); 68 | let greatGrandChild3: DisplayObject = new DisplayObject(); 69 | 70 | container.addChild(child1); 71 | container.addChild(child2); 72 | container.addChild(child3); 73 | 74 | child1.addChild(grandChild1); 75 | child1.addChild(grandChild2); 76 | child1.addChild(grandChild3); 77 | 78 | grandChild1.addChild(greatGrandChild1); 79 | grandChild1.addChild(greatGrandChild2); 80 | grandChild1.addChild(greatGrandChild3); 81 | 82 | assert.isTrue(container.contains(child1)); 83 | assert.isTrue(container.contains(child2)); 84 | assert.isTrue(container.contains(child3)); 85 | 86 | assert.isTrue(container.contains(grandChild1)); 87 | assert.isTrue(container.contains(grandChild2)); 88 | assert.isTrue(container.contains(grandChild3)); 89 | 90 | assert.isTrue(container.contains(greatGrandChild1)); 91 | assert.isTrue(container.contains(greatGrandChild2)); 92 | assert.isTrue(container.contains(greatGrandChild3)); 93 | }); 94 | 95 | it("Container_does_not_contains_ancestors", () => { 96 | let parent: Container = new Container(); 97 | let grandParent: Container = new Container(); 98 | let greatGrandParent: Container = new Container(); 99 | 100 | parent.addChild(container); 101 | grandParent.addChild(parent); 102 | greatGrandParent.addChild(grandParent); 103 | 104 | assert.isFalse(container.contains(parent)); 105 | assert.isFalse(container.contains(grandParent)); 106 | assert.isFalse(container.contains(greatGrandParent)); 107 | }); 108 | 109 | it("Container_does_not_contains_same_level_container", () => { 110 | let parent: Container = new Container(); 111 | let brother: Container = new Container(); 112 | let sister: Container = new Container(); 113 | 114 | parent.addChild(container); 115 | parent.addChild(brother); 116 | parent.addChild(sister); 117 | 118 | assert.isFalse(container.contains(parent)); 119 | assert.isFalse(container.contains(brother)); 120 | assert.isFalse(container.contains(sister)); 121 | }); 122 | }); 123 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/contextView/pixiPatch/eventemitter3Patch.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Container } from "pixi.js"; 13 | 14 | import { Event } from "@robotlegsjs/core"; 15 | 16 | import "../../../../../../src/robotlegs/bender/extensions/contextView/pixiPatch/eventemitter3-patch"; 17 | 18 | describe("EventEmmiter3Patch", () => { 19 | let container: Container; 20 | 21 | beforeEach(() => { 22 | container = new Container(); 23 | }); 24 | 25 | afterEach(() => { 26 | container = null; 27 | }); 28 | 29 | it("DisplayObject_is_a_EventDispatcher", () => { 30 | assert.isNotNull(container.addEventListener); 31 | assert.isFunction(container.addEventListener); 32 | assert.isNotNull(container.hasEventListener); 33 | assert.isFunction(container.hasEventListener); 34 | assert.isNotNull(container.removeEventListener); 35 | assert.isFunction(container.removeEventListener); 36 | assert.isNotNull(container.willTrigger); 37 | assert.isFunction(container.willTrigger); 38 | assert.isNotNull(container.dispatchEvent); 39 | assert.isFunction(container.dispatchEvent); 40 | }); 41 | 42 | it("addEventListener_store_listener", () => { 43 | let listener: Function = () => { 44 | // no nothing 45 | return; 46 | }; 47 | container.addEventListener("added", listener); 48 | assert.deepEqual(container.listeners("added"), [listener]); 49 | }); 50 | 51 | it("hasEventListener_check_if_a_listener_was_added", () => { 52 | let listener: Function = () => { 53 | // no nothing 54 | return; 55 | }; 56 | container.addEventListener("added", listener); 57 | assert.isTrue(container.hasEventListener("added", listener)); 58 | assert.isFalse(container.hasEventListener("removed")); 59 | }); 60 | 61 | it("removeEventListener_remove_a_listener", () => { 62 | let listener: Function = () => { 63 | // no nothing 64 | return; 65 | }; 66 | container.addEventListener("added", listener); 67 | container.removeEventListener("added", listener); 68 | assert.isEmpty(container.listeners("added")); 69 | assert.isFalse(container.hasEventListener("added")); 70 | }); 71 | 72 | it("willTrigger_ensure_that_a_event_will_be_dispatched", () => { 73 | let listener: Function = () => { 74 | // no nothing 75 | return; 76 | }; 77 | container.addEventListener("added", listener); 78 | assert.isTrue(container.willTrigger("added")); 79 | }); 80 | 81 | it("dispatchEvent_dispatch_a_event", () => { 82 | let dispatched: boolean = false; 83 | let listener: Function = () => { 84 | dispatched = true; 85 | }; 86 | container.addEventListener("added", listener); 87 | container.dispatchEvent(new Event("added")); 88 | assert.isTrue(dispatched); 89 | }); 90 | 91 | it("dispatchEvent_dispatch_a_event_with_bubbles", () => { 92 | let dispatched: boolean = false; 93 | let listener: Function = () => { 94 | dispatched = true; 95 | }; 96 | let child: Container = new Container(); 97 | let grandChild: Container = new Container(); 98 | child.addChild(grandChild); 99 | container.addChild(child); 100 | container.addEventListener("test", listener); 101 | grandChild.dispatchEvent(new Event("test", true)); 102 | assert.isTrue(dispatched); 103 | }); 104 | }); 105 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/contextView/support/CallbackLogTarget.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { ILogTarget } from "@robotlegsjs/core"; 9 | 10 | import { LogParams } from "./LogParams"; 11 | 12 | export class CallbackLogTarget implements ILogTarget { 13 | protected _callback: Function; 14 | 15 | constructor(callback: Function) { 16 | this._callback = callback; 17 | } 18 | 19 | public log(source: any, level: number, timestamp: number, message: string, params: any[]): void { 20 | if (this._callback) { 21 | this._callback(new LogParams(source, level, timestamp, message, params)); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/contextView/support/LogParams.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | export class LogParams { 9 | constructor(public source: any, public level: number, public timestamp: number, public message: string, public params: any[]) { 10 | this.source = source; 11 | this.level = level; 12 | this.timestamp = timestamp; 13 | this.message = message; 14 | this.params = params; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/impl/mediatorMap.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Sprite, Texture } from "pixi.js"; 13 | 14 | import { IContext, Context, TypeMatcher } from "@robotlegsjs/core"; 15 | 16 | import { IMediatorMapper } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/dsl/IMediatorMapper"; 17 | import { MediatorMap } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMap"; 18 | import { MediatorMapper } from "../../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMapper"; 19 | 20 | describe("MediatorMap", () => { 21 | let context: IContext = null; 22 | let mediatorMap: MediatorMap = null; 23 | 24 | beforeEach(() => { 25 | context = new Context(); 26 | mediatorMap = new MediatorMap(context); 27 | }); 28 | 29 | afterEach(() => { 30 | if (context.initialized) { 31 | context.destroy(); 32 | } 33 | 34 | context = null; 35 | mediatorMap = null; 36 | }); 37 | 38 | it("mapMatcher_creates_mapper", () => { 39 | const matcher: TypeMatcher = new TypeMatcher().allOf(Sprite); 40 | assert.instanceOf(mediatorMap.mapMatcher(matcher), MediatorMapper); 41 | }); 42 | 43 | it("mapMatcher_to_matching_TypeMatcher_returns_same_mapper", () => { 44 | const matcher1: TypeMatcher = new TypeMatcher().allOf(Sprite); 45 | const matcher2: TypeMatcher = new TypeMatcher().allOf(Sprite); 46 | const mapper1: IMediatorMapper = mediatorMap.mapMatcher(matcher1); 47 | const mapper2: IMediatorMapper = mediatorMap.mapMatcher(matcher2); 48 | assert.equal(mapper1, mapper2); 49 | }); 50 | 51 | it("mapMatcher_to_differing_TypeMatcher_returns_different_mapper", () => { 52 | const matcher1: TypeMatcher = new TypeMatcher().allOf(Sprite); 53 | const matcher2: TypeMatcher = new TypeMatcher().allOf(Texture); 54 | const mapper1: IMediatorMapper = mediatorMap.mapMatcher(matcher1); 55 | const mapper2: IMediatorMapper = mediatorMap.mapMatcher(matcher2); 56 | assert.notEqual(mapper1, mapper2); 57 | }); 58 | 59 | it("map_creates_mapper", () => { 60 | assert.instanceOf(mediatorMap.map(Sprite), MediatorMapper); 61 | }); 62 | 63 | it("map_to_matching_TypeMatcher_returns_same_mapper", () => { 64 | const mapper1: IMediatorMapper = mediatorMap.map(Sprite); 65 | const mapper2: IMediatorMapper = mediatorMap.map(Sprite); 66 | assert.equal(mapper1, mapper2); 67 | }); 68 | 69 | it("map_to_differing_TypeMatcher_returns_different_mapper", () => { 70 | const mapper1: IMediatorMapper = mediatorMap.map(Sprite); 71 | const mapper2: IMediatorMapper = mediatorMap.map(Texture); 72 | assert.notEqual(mapper1, mapper2); 73 | }); 74 | 75 | it("unmapMatcher_returns_mapper", () => { 76 | const mapper: MediatorMapper = mediatorMap.mapMatcher(new TypeMatcher().allOf(Sprite)); 77 | const unmappedMapper: MediatorMapper = mediatorMap.unmapMatcher(new TypeMatcher().allOf(Sprite)); 78 | assert.equal(unmappedMapper, mapper); 79 | }); 80 | 81 | it("unmap_returns_mapper", () => { 82 | const mapper: MediatorMapper = mediatorMap.map(Sprite); 83 | const unmappedMapper: MediatorMapper = mediatorMap.unmap(Sprite); 84 | assert.equal(unmappedMapper, mapper); 85 | }); 86 | 87 | it("robust_to_unmapping_non_existent_mappings", () => { 88 | mediatorMap.unmapMatcher(new TypeMatcher().allOf(Sprite)).fromAll(); 89 | }); 90 | }); 91 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/mediatorMapExtension.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { IContext, Context } from "@robotlegsjs/core"; 13 | 14 | import { ViewManagerExtension, MediatorMapExtension, IMediatorMap } from "../../../../../src"; 15 | 16 | import { MediatorMap } from "../../../../../src/robotlegs/bender/extensions/mediatorMap/impl/MediatorMap"; 17 | 18 | describe("MediatorMapExtension", () => { 19 | let context: IContext; 20 | 21 | beforeEach(() => { 22 | context = new Context(); 23 | }); 24 | 25 | afterEach(() => { 26 | context.destroy(); 27 | context = null; 28 | }); 29 | 30 | it("installing_after_initialization_throws_error", () => { 31 | function installExtensionAfterInitialization(): void { 32 | context.initialize(); 33 | context.install(MediatorMapExtension); 34 | } 35 | assert.throws(installExtensionAfterInitialization, Error); 36 | }); 37 | 38 | it("mediatorMap_is_mapped_into_injector_on_initialize", () => { 39 | let mediatorMap: IMediatorMap = null; 40 | context.install(ViewManagerExtension, MediatorMapExtension); 41 | context.whenInitializing(function(): void { 42 | mediatorMap = context.injector.get(IMediatorMap); 43 | }); 44 | context.initialize(); 45 | assert.isNotNull(mediatorMap); 46 | assert.instanceOf(mediatorMap, MediatorMap); 47 | }); 48 | 49 | it("mediatorMap_is_mapped_into_injector_on_initialize_when_view_manager_is_not_installed", () => { 50 | let mediatorMap: IMediatorMap = null; 51 | context.install(MediatorMapExtension); 52 | context.whenInitializing(function(): void { 53 | mediatorMap = context.injector.get(IMediatorMap); 54 | }); 55 | context.initialize(); 56 | assert.isNotNull(mediatorMap); 57 | assert.instanceOf(mediatorMap, MediatorMap); 58 | }); 59 | 60 | it("mediatorMap_is_unmapped_from_injector_on_destroy", () => { 61 | context.install(ViewManagerExtension, MediatorMapExtension); 62 | context.afterDestroying(function(): void { 63 | assert.isFalse(context.injector.isBound(IMediatorMap)); 64 | }); 65 | context.initialize(); 66 | context.destroy(); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/Alpha50PercentHook.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Sprite } from "pixi.js"; 9 | 10 | import { injectable, inject, IHook } from "@robotlegsjs/core"; 11 | 12 | @injectable() 13 | export class Alpha50PercentHook implements IHook { 14 | @inject(Sprite) 15 | public view: Sprite; 16 | 17 | public hook(): void { 18 | this.view.alpha = 0.5; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/CallbackHook.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject, named, IHook } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class CallbackHook implements IHook { 12 | private _callback: Function; 13 | 14 | constructor( 15 | @inject("Function") 16 | @named("hookCallback") 17 | callback: Function 18 | ) { 19 | this._callback = callback; 20 | } 21 | 22 | public hook(): void { 23 | if (this._callback) { 24 | this._callback(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/CallbackMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject, named, optional } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class CallbackMediator { 12 | @inject("Function") 13 | @named("executeCallback") 14 | @optional() 15 | public callback: Function; 16 | 17 | public initialize(): void { 18 | if (this.callback) { 19 | this.callback(this); 20 | } 21 | } 22 | 23 | public destroy(): void {} 24 | } 25 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/EmptyMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class EmptyMediator {} 12 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/ExampleDisplayObjectMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject } from "@robotlegsjs/core"; 9 | 10 | import { DisplayObject } from "pixi.js"; 11 | 12 | import { MediatorWatcher } from "./MediatorWatcher"; 13 | 14 | @injectable() 15 | export class ExampleDisplayObjectMediator { 16 | @inject(MediatorWatcher) 17 | public mediatorWatcher: MediatorWatcher; 18 | 19 | @inject(DisplayObject) 20 | public view: DisplayObject; 21 | 22 | public initialize(): void { 23 | this.mediatorWatcher.notify("ExampleDisplayObjectMediator"); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/ExampleMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject } from "@robotlegsjs/core"; 9 | 10 | import { Sprite } from "pixi.js"; 11 | 12 | import { MediatorWatcher } from "./MediatorWatcher"; 13 | 14 | @injectable() 15 | export class ExampleMediator { 16 | @inject(MediatorWatcher) 17 | public mediatorWatcher: MediatorWatcher; 18 | 19 | @inject(Sprite) 20 | public view: Sprite; 21 | 22 | public initialize(): void { 23 | this.mediatorWatcher.notify("ExampleMediator"); 24 | } 25 | 26 | public destroy(): void { 27 | this.mediatorWatcher.notify("ExampleMediator destroy"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/ExampleMediator2.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject } from "@robotlegsjs/core"; 9 | 10 | import { Sprite } from "pixi.js"; 11 | 12 | import { MediatorWatcher } from "./MediatorWatcher"; 13 | 14 | @injectable() 15 | export class ExampleMediator2 { 16 | @inject(MediatorWatcher) 17 | public mediatorWatcher: MediatorWatcher; 18 | 19 | @inject(Sprite) 20 | public view: Sprite; 21 | 22 | public initialize(): void { 23 | this.mediatorWatcher.notify("ExampleMediator2"); 24 | } 25 | 26 | public destroy(): void { 27 | this.mediatorWatcher.notify("ExampleMediator2 destroy"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/GrumpyGuard.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, IGuard } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class GrumpyGuard implements IGuard { 12 | public approve(): boolean { 13 | return false; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/HappyGuard.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, IGuard } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class HappyGuard implements IGuard { 12 | public approve(): boolean { 13 | return true; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/HookWithMediatorAndViewInjectionReportFunction.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Sprite } from "pixi.js"; 9 | 10 | import { injectable, inject, named, IHook } from "@robotlegsjs/core"; 11 | 12 | import { RectangleMediator } from "./RectangleMediator"; 13 | 14 | @injectable() 15 | export class HookWithMediatorAndViewInjectionReportFunction implements IHook { 16 | @inject(RectangleMediator) 17 | public mediator: RectangleMediator; 18 | 19 | @inject(Sprite) 20 | public view: Sprite; 21 | 22 | @inject("Function") 23 | @named("reportView") 24 | public reportView: Function; 25 | 26 | public hook(): void { 27 | this.reportView(this.view, this.mediator.width, this.mediator.height); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/InjectedMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class InjectedMediator { 12 | @inject(Number) 13 | public number: number; 14 | 15 | public initialize(): void {} 16 | 17 | public destroy(): void {} 18 | } 19 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/LifecycleReportingMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject, named, optional } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class LifecycleReportingMediator { 12 | @inject("Function") 13 | @named("preInitializeCallback") 14 | @optional() 15 | public preInitializeCallback: Function; 16 | 17 | @inject("Function") 18 | @named("initializeCallback") 19 | @optional() 20 | public initializeCallback: Function; 21 | 22 | @inject("Function") 23 | @named("postInitializeCallback") 24 | @optional() 25 | public postInitializeCallback: Function; 26 | 27 | @inject("Function") 28 | @named("preDestroyCallback") 29 | @optional() 30 | public preDestroyCallback: Function; 31 | 32 | @inject("Function") 33 | @named("destroyCallback") 34 | @optional() 35 | public destroyCallback: Function; 36 | 37 | @inject("Function") 38 | @named("postDestroyCallback") 39 | @optional() 40 | public postDestroyCallback: Function; 41 | 42 | public initialized: Boolean = false; 43 | 44 | public destroyed: Boolean = false; 45 | 46 | public view: any = undefined; 47 | 48 | /*============================================================================*/ 49 | /* Public Functions */ 50 | /*============================================================================*/ 51 | 52 | public preInitialize(): void { 53 | if (this.preInitializeCallback) { 54 | this.preInitializeCallback("preInitialize"); 55 | } 56 | } 57 | 58 | public initialize(): void { 59 | this.initialized = true; 60 | if (this.initializeCallback) { 61 | this.initializeCallback("initialize"); 62 | } 63 | } 64 | 65 | public postInitialize(): void { 66 | if (this.postInitializeCallback) { 67 | this.postInitializeCallback("postInitialize"); 68 | } 69 | } 70 | 71 | public preDestroy(): void { 72 | if (this.preDestroyCallback) { 73 | this.preDestroyCallback("preDestroy"); 74 | } 75 | } 76 | 77 | public destroy(): void { 78 | this.destroyed = true; 79 | if (this.destroyCallback) { 80 | this.destroyCallback("destroy"); 81 | } 82 | } 83 | 84 | public postDestroy(): void { 85 | if (this.postDestroyCallback) { 86 | this.postDestroyCallback("postDestroy"); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/MediatorHook.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Sprite } from "pixi.js"; 9 | 10 | import { injectable, inject, named, optional, IHook } from "@robotlegsjs/core"; 11 | 12 | import { ViewInjectedMediator } from "./ViewInjectedMediator"; 13 | 14 | @injectable() 15 | export class MediatorHook implements IHook { 16 | @inject("Function") 17 | @named("callback") 18 | @optional() 19 | public callback: Function; 20 | 21 | @inject(Sprite) 22 | public mediatedItem: Sprite; 23 | 24 | @inject(ViewInjectedMediator) 25 | public mediator: ViewInjectedMediator; 26 | 27 | public hook(): void { 28 | if (this.callback) { 29 | this.callback(this); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/MediatorWatcher.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class MediatorWatcher { 12 | protected _notifications: string[] = []; 13 | 14 | public get notifications(): string[] { 15 | return this._notifications; 16 | } 17 | 18 | public notify(message: string): void { 19 | this._notifications.push(message); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/NotAView.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class NotAView { 12 | public mediatorName: string; 13 | } 14 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/NotAViewMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject } from "@robotlegsjs/core"; 9 | 10 | import { MediatorWatcher } from "./MediatorWatcher"; 11 | import { NotAView } from "./NotAView"; 12 | 13 | @injectable() 14 | export class NotAViewMediator { 15 | @inject(MediatorWatcher) 16 | public mediatorWatcher: MediatorWatcher; 17 | 18 | @inject(NotAView) 19 | public view: NotAView; 20 | 21 | public initialize(): void { 22 | this.view.mediatorName = "NotAViewMediator"; 23 | this.mediatorWatcher.notify("NotAViewMediator"); 24 | } 25 | 26 | public destroy(): void { 27 | this.mediatorWatcher.notify("NotAViewMediator destroy"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/NullMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class NullMediator {} 12 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/NullMediator2.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class NullMediator2 {} 12 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/OnlyIfViewHasChildrenGuard.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Sprite } from "pixi.js"; 9 | 10 | import { injectable, inject, IGuard } from "@robotlegsjs/core"; 11 | 12 | @injectable() 13 | export class OnlyIfViewHasChildrenGuard implements IGuard { 14 | @inject(Sprite) 15 | public view: Sprite; 16 | 17 | public approve(): boolean { 18 | return this.view.children.length > 0; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/RectangleMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject, named } from "@robotlegsjs/core"; 9 | 10 | @injectable() 11 | export class RectangleMediator { 12 | @inject(Number) 13 | @named("width") 14 | public width: number; 15 | 16 | @inject(Number) 17 | @named("height") 18 | public height: number; 19 | } 20 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/ViewInjectedAsRequestedMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject } from "@robotlegsjs/core"; 9 | 10 | import { DisplayObject } from "pixi.js"; 11 | 12 | @injectable() 13 | export class ViewInjectedAsRequestedMediator { 14 | @inject(DisplayObject) 15 | public mediatedItem: DisplayObject; 16 | 17 | public initialize(): void {} 18 | 19 | public destroy(): void {} 20 | } 21 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/mediatorMap/support/ViewInjectedMediator.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { injectable, inject } from "@robotlegsjs/core"; 9 | 10 | import { Sprite } from "pixi.js"; 11 | 12 | @injectable() 13 | export class ViewInjectedMediator { 14 | @inject(Sprite) 15 | public mediatedItem: Sprite; 16 | 17 | public initialize(): void {} 18 | 19 | public destroy(): void {} 20 | } 21 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/viewManager/impl/configureViewEvent.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Container } from "pixi.js"; 13 | 14 | import { ConfigureViewEvent } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ConfigureViewEvent"; 15 | 16 | describe("ConfigureViewEvent", () => { 17 | let container: Container = null; 18 | let event: ConfigureViewEvent = null; 19 | 20 | beforeEach(() => { 21 | container = new Container(); 22 | event = new ConfigureViewEvent(ConfigureViewEvent.CONFIGURE_VIEW, container); 23 | }); 24 | 25 | afterEach(() => { 26 | container = null; 27 | event = null; 28 | }); 29 | 30 | it("ensure_static_properties_will_not_change", () => { 31 | assert.equal(ConfigureViewEvent.CONFIGURE_VIEW, "configureView"); 32 | }); 33 | 34 | it("type_is_stored", () => { 35 | assert.equal(event.type, ConfigureViewEvent.CONFIGURE_VIEW); 36 | }); 37 | 38 | it("view_is_stored", () => { 39 | assert.equal(event.view, container); 40 | }); 41 | 42 | it("event_is_cloned", () => { 43 | let clone: ConfigureViewEvent = event.clone(); 44 | assert.equal(clone.type, event.type); 45 | assert.equal(clone.view, event.view); 46 | assert.notEqual(clone, event); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/viewManager/impl/containerBindingEvent.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { ContainerBindingEvent } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ContainerBindingEvent"; 13 | 14 | describe("ContainerBindingEvent", () => { 15 | let event: ContainerBindingEvent = null; 16 | 17 | beforeEach(() => { 18 | event = new ContainerBindingEvent(ContainerBindingEvent.BINDING_EMPTY); 19 | }); 20 | 21 | afterEach(() => { 22 | event = null; 23 | }); 24 | 25 | it("ensure_static_properties_will_not_change", () => { 26 | assert.equal(ContainerBindingEvent.BINDING_EMPTY, "bindingEmpty"); 27 | }); 28 | 29 | it("type_is_stored", () => { 30 | assert.equal(event.type, ContainerBindingEvent.BINDING_EMPTY); 31 | }); 32 | 33 | it("event_is_cloned", () => { 34 | let clone: ContainerBindingEvent = event.clone(); 35 | assert.equal(clone.type, event.type); 36 | assert.notEqual(clone, event); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/viewManager/impl/containerRegistryEvent.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Sprite } from "pixi.js"; 13 | 14 | import { ContainerRegistryEvent } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ContainerRegistryEvent"; 15 | 16 | describe("ContainerRegistryEvent", () => { 17 | let container: Sprite = null; 18 | let event: ContainerRegistryEvent = null; 19 | 20 | beforeEach(() => { 21 | container = new Sprite(); 22 | event = new ContainerRegistryEvent(ContainerRegistryEvent.CONTAINER_ADD, container); 23 | }); 24 | 25 | afterEach(() => { 26 | container = null; 27 | event = null; 28 | }); 29 | 30 | it("ensure_static_properties_will_not_change", () => { 31 | assert.equal(ContainerRegistryEvent.CONTAINER_ADD, "containerAdd"); 32 | assert.equal(ContainerRegistryEvent.CONTAINER_REMOVE, "containerRemove"); 33 | assert.equal(ContainerRegistryEvent.ROOT_CONTAINER_ADD, "rootContainerAdd"); 34 | assert.equal(ContainerRegistryEvent.ROOT_CONTAINER_REMOVE, "rootContainerRemove"); 35 | }); 36 | 37 | it("type_is_stored", () => { 38 | assert.equal(event.type, ContainerRegistryEvent.CONTAINER_ADD); 39 | }); 40 | 41 | it("container_is_stored", () => { 42 | assert.equal(event.container, container); 43 | }); 44 | 45 | it("event_is_cloned", () => { 46 | let clone: ContainerRegistryEvent = event.clone(); 47 | assert.equal(clone.type, event.type); 48 | assert.equal(clone.container, event.container); 49 | assert.notEqual(clone, event); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/viewManager/impl/viewManagerEvent.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { Sprite } from "pixi.js"; 13 | 14 | import { IViewHandler } from "../../../../../../src/robotlegs/bender/extensions/viewManager/api/IViewHandler"; 15 | import { ViewManagerEvent } from "../../../../../../src/robotlegs/bender/extensions/viewManager/impl/ViewManagerEvent"; 16 | 17 | import { CallbackViewHandler } from "../support/CallbackViewHandler"; 18 | 19 | describe("ViewManagerEvent", () => { 20 | let container: Sprite = null; 21 | let handler: IViewHandler = null; 22 | let event: ViewManagerEvent = null; 23 | 24 | beforeEach(() => { 25 | container = new Sprite(); 26 | handler = new CallbackViewHandler(); 27 | event = new ViewManagerEvent(ViewManagerEvent.CONTAINER_ADD, container, handler); 28 | }); 29 | 30 | afterEach(() => { 31 | container = null; 32 | handler = null; 33 | event = null; 34 | }); 35 | 36 | it("ensure_static_properties_will_not_change", () => { 37 | assert.equal(ViewManagerEvent.CONTAINER_ADD, "containerAdd"); 38 | assert.equal(ViewManagerEvent.CONTAINER_REMOVE, "containerRemove"); 39 | assert.equal(ViewManagerEvent.HANDLER_ADD, "handlerAdd"); 40 | assert.equal(ViewManagerEvent.HANDLER_REMOVE, "handlerRemove"); 41 | }); 42 | 43 | it("type_is_stored", () => { 44 | assert.equal(event.type, ViewManagerEvent.CONTAINER_ADD); 45 | }); 46 | 47 | it("container_is_stored", () => { 48 | assert.equal(event.container, container); 49 | }); 50 | 51 | it("handler_is_stored", () => { 52 | assert.equal(event.handler, handler); 53 | }); 54 | 55 | it("event_is_cloned", () => { 56 | let clone: ViewManagerEvent = event.clone(); 57 | assert.equal(clone.type, event.type); 58 | assert.equal(clone.container, event.container); 59 | assert.equal(clone.handler, event.handler); 60 | assert.notEqual(clone, event); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/viewManager/manualStageObserverExtension.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { IContext, Context, LogLevel } from "@robotlegsjs/core"; 13 | 14 | import { ManualStageObserverExtension, ViewManagerExtension } from "../../../../../src"; 15 | 16 | import { CallbackLogTarget } from "../contextView/support/CallbackLogTarget"; 17 | import { LogParams } from "../contextView/support/LogParams"; 18 | 19 | describe("ManualStageObserverExtension", () => { 20 | let context: IContext; 21 | 22 | beforeEach(() => { 23 | context = new Context(); 24 | }); 25 | 26 | afterEach(() => { 27 | context.destroy(); 28 | context = null; 29 | }); 30 | 31 | it("installing_after_initialization_throws_error", () => { 32 | function installExtensionAfterInitialization(): void { 33 | context.initialize(); 34 | context.install(ManualStageObserverExtension); 35 | } 36 | assert.throws(installExtensionAfterInitialization, Error); 37 | }); 38 | 39 | it("extension_logs_debug_messages_when_initializing_and_destroying", () => { 40 | let whenInitializingLogged: boolean = false; 41 | let whenDestroyingLogged: boolean = false; 42 | let logTarget: CallbackLogTarget = new CallbackLogTarget((log: LogParams) => { 43 | if (log.source instanceof ManualStageObserverExtension && log.level === LogLevel.DEBUG) { 44 | if (!whenInitializingLogged) { 45 | whenInitializingLogged = log.message === "Creating genuine ManualStageObserver Singleton"; 46 | } 47 | if (!whenDestroyingLogged) { 48 | whenDestroyingLogged = log.message === "Destroying genuine ManualStageObserver Singleton"; 49 | } 50 | } 51 | }); 52 | context.logLevel = LogLevel.DEBUG; 53 | context.install(ViewManagerExtension, ManualStageObserverExtension); 54 | context.addLogTarget(logTarget); 55 | context.initialize(); 56 | context.destroy(); 57 | assert.isTrue(whenInitializingLogged); 58 | assert.isTrue(whenDestroyingLogged); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/viewManager/stageObserverExtension.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { IContext, Context, LogLevel } from "@robotlegsjs/core"; 13 | 14 | import { StageObserverExtension, ViewManagerExtension } from "../../../../../src"; 15 | 16 | import { CallbackLogTarget } from "../contextView/support/CallbackLogTarget"; 17 | import { LogParams } from "../contextView/support/LogParams"; 18 | 19 | describe("StageObserverExtension", () => { 20 | let context: IContext; 21 | 22 | beforeEach(() => { 23 | context = new Context(); 24 | }); 25 | 26 | afterEach(() => { 27 | context.destroy(); 28 | context = null; 29 | }); 30 | 31 | it("installing_after_initialization_throws_error", () => { 32 | function installExtensionAfterInitialization(): void { 33 | context.initialize(); 34 | context.install(StageObserverExtension); 35 | } 36 | assert.throws(installExtensionAfterInitialization, Error); 37 | }); 38 | 39 | it("extension_logs_debug_messages_when_initializing_and_destroying", () => { 40 | let whenInitializingLogged: boolean = false; 41 | let whenDestroyingLogged: boolean = false; 42 | let logTarget: CallbackLogTarget = new CallbackLogTarget((log: LogParams) => { 43 | if (log.source instanceof StageObserverExtension && log.level === LogLevel.DEBUG) { 44 | if (!whenInitializingLogged) { 45 | whenInitializingLogged = log.message === "Creating genuine StageObserver Singleton"; 46 | } 47 | if (!whenDestroyingLogged) { 48 | whenDestroyingLogged = log.message === "Destroying genuine StageObserver Singleton"; 49 | } 50 | } 51 | }); 52 | context.logLevel = LogLevel.DEBUG; 53 | context.install(ViewManagerExtension, StageObserverExtension); 54 | context.addLogTarget(logTarget); 55 | context.initialize(); 56 | context.destroy(); 57 | assert.isTrue(whenInitializingLogged); 58 | assert.isTrue(whenDestroyingLogged); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/viewManager/support/CallbackViewHandler.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Container } from "pixi.js"; 9 | 10 | import { IClass } from "@robotlegsjs/core"; 11 | 12 | import { IViewHandler } from "../../../../../../src/robotlegs/bender/extensions/viewManager/api/IViewHandler"; 13 | 14 | /** 15 | * @private 16 | */ 17 | export class CallbackViewHandler implements IViewHandler { 18 | private _callback: Function; 19 | 20 | constructor(callback: Function = null) { 21 | this._callback = callback; 22 | } 23 | 24 | public handleView(view: Container, type: IClass): void { 25 | if (this._callback) { 26 | this._callback(view, type); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/viewManager/support/TreeContainer.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import { Sprite } from "pixi.js"; 9 | 10 | /** 11 | * @private 12 | */ 13 | export class TreeContainer extends Sprite { 14 | private _treeDepth: number = 0; 15 | private _treeWidth: number = 0; 16 | private _treeChildren: TreeContainer[] = []; 17 | 18 | constructor(treeDetpth: number, treeWidth: number) { 19 | super(); 20 | 21 | this._treeDepth = treeDetpth; 22 | this._treeWidth = treeWidth; 23 | 24 | this.populate(); 25 | } 26 | 27 | private populate(): void { 28 | if (this._treeDepth > 0) { 29 | for (let i: number = 0; i < this._treeWidth; i++) { 30 | let child: TreeContainer = new TreeContainer(this._treeDepth - 1, this._treeWidth); 31 | this._treeChildren.push(child); 32 | this.addChild(child); 33 | } 34 | } 35 | } 36 | 37 | public get treeChildren(): TreeContainer[] { 38 | return this._treeChildren; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/robotlegs/bender/extensions/viewManager/viewManagerExtension.test.ts: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // Copyright (c) 2017-present, RobotlegsJS. All Rights Reserved. 3 | // 4 | // NOTICE: You are permitted to use, modify, and distribute this file 5 | // in accordance with the terms of the license agreement accompanying it. 6 | // ------------------------------------------------------------------------------ 7 | 8 | import "../../../../entry"; 9 | 10 | import { assert } from "chai"; 11 | 12 | import { IContext, Context } from "@robotlegsjs/core"; 13 | 14 | import { ViewManagerExtension, IViewManager } from "../../../../../src"; 15 | 16 | import { ViewManager } from "../../../../../src/robotlegs/bender/extensions/viewManager/impl/ViewManager"; 17 | 18 | describe("ViewManagerExtension", () => { 19 | let context: IContext; 20 | 21 | beforeEach(() => { 22 | context = new Context(); 23 | }); 24 | 25 | afterEach(() => { 26 | context.destroy(); 27 | context = null; 28 | }); 29 | 30 | it("installing after initialization throws error", () => { 31 | function installExtensionAfterInitialization(): void { 32 | context.initialize(); 33 | context.install(ViewManagerExtension); 34 | } 35 | assert.throws(installExtensionAfterInitialization, Error); 36 | }); 37 | 38 | it("viewManager is mapped into injector", () => { 39 | let viewManager: IViewManager = null; 40 | context.install(ViewManagerExtension); 41 | context.whenInitializing(function(): void { 42 | viewManager = context.injector.get(IViewManager); 43 | }); 44 | context.initialize(); 45 | assert.isNotNull(viewManager); 46 | assert.instanceOf(viewManager, ViewManager); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.test.json" 3 | } 4 | -------------------------------------------------------------------------------- /tsconfig.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "lib-example" 5 | }, 6 | "include": [ 7 | "./src/**/*.ts", 8 | "./example/**/*.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "lib", 4 | "target": "es5", 5 | "lib": ["es7", "dom"], 6 | "types": ["reflect-metadata"], 7 | "sourceMap": true, 8 | "inlineSources": true, 9 | "module": "commonjs", 10 | "moduleResolution": "node", 11 | "experimentalDecorators": true, 12 | "emitDecoratorMetadata": true, 13 | "removeComments": false, 14 | "strict": false, 15 | "noImplicitAny": true, 16 | "strictNullChecks": false, 17 | "noImplicitThis": false, 18 | "alwaysStrict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": false, 21 | "noImplicitReturns": true, 22 | "noFallthroughCasesInSwitch": true 23 | }, 24 | "include": [ 25 | "./src/**/*.ts" 26 | ], 27 | "files": [ 28 | "./definitions/pixi.d.ts" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "lib-test" 5 | }, 6 | "include": [ 7 | "./src/**/*.ts", 8 | "./test/**/*.ts" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /tslint.example.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "./tslint.json" 4 | ], 5 | "rules": { 6 | "no-reference": false, 7 | "object-literal-sort-keys": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint:latest", 4 | "tslint-config-prettier" 5 | ], 6 | "rules": { 7 | "ban-types": [ false ], 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "forin": true, 15 | "label-position": true, 16 | "member-access": true, 17 | "member-ordering": [ 18 | true, { 19 | "order": [ 20 | "static-field", 21 | "instance-field", 22 | "constructor", 23 | "public-instance-method", 24 | "protected-instance-method", 25 | "private-instance-method" 26 | ] 27 | } 28 | ], 29 | "no-angle-bracket-type-assertion": false, 30 | "no-arg": true, 31 | "no-bitwise": true, 32 | "no-console": [ 33 | true, 34 | "debug", 35 | "info", 36 | "time", 37 | "timeEnd", 38 | "trace" 39 | ], 40 | "no-construct": true, 41 | "no-debugger": true, 42 | "no-duplicate-variable": true, 43 | "no-empty": false, 44 | "no-eval": true, 45 | "no-inferrable-types": false, 46 | "no-shadowed-variable": true, 47 | "no-string-literal": true, 48 | "no-switch-case-fall-through": false, 49 | "no-this-assignment": false, 50 | "no-unused-expression": true, 51 | "no-use-before-declare": true, 52 | "no-var-keyword": true, 53 | "object-literal-sort-keys": true, 54 | "ordered-imports": false, 55 | "only-arrow-functions": [ false ], 56 | "prefer-const": false, 57 | "radix":true, 58 | "trailing-comma": [ 59 | false 60 | ], 61 | "triple-equals": [ 62 | true, 63 | "allow-null-check" 64 | ], 65 | "variable-name": false 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tslint.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "./tslint.json" 4 | ], 5 | "rules": { 6 | "no-implicit-dependencies": [true, "dev"], 7 | "no-reference": false, 8 | "no-submodule-imports": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | const TerserPlugin = require("terser-webpack-plugin"); 4 | 5 | module.exports = env => { 6 | if (!env) env = { production: false, karma: false }; 7 | 8 | let mode = env.production ? "production" : "development"; 9 | let tsconfig = !env.karma ? "tsconfig.json" : "tsconfig.test.json"; 10 | let output = env.production ? "dist" : "dist-test"; 11 | let filename = env.karma ? "[name].[hash].js" : env.production ? "robotlegs-pixi.min.js" : "robotlegs-pixi.js"; 12 | 13 | return { 14 | mode: mode, 15 | 16 | entry: { 17 | main: path.join(__dirname, "src/index.ts") 18 | }, 19 | 20 | output: { 21 | path: path.join(__dirname, output), 22 | filename: filename, 23 | 24 | libraryTarget: "var", 25 | library: "RobotlegsJSPixi" 26 | }, 27 | 28 | devtool: env.production ? undefined : "inline-source-map", 29 | 30 | module: { 31 | rules: [ 32 | { 33 | test: /\.ts$/, 34 | loader: "ts-loader?configFile=" + tsconfig 35 | }, 36 | { 37 | test: env.production /* disable this loader for production builds */ ? /^$/ : /^.*(src).*\.ts$/, 38 | loader: "istanbul-instrumenter-loader", 39 | query: { 40 | embedSource: true 41 | }, 42 | enforce: "post" 43 | } 44 | ] 45 | }, 46 | 47 | plugins: env.production ? [] : [new webpack.SourceMapDevToolPlugin({ test: /\.ts$/i })], 48 | 49 | optimization: env.production 50 | ? { 51 | concatenateModules: true, 52 | minimize: true, 53 | minimizer: [ 54 | new TerserPlugin({ 55 | cache: true, 56 | parallel: 4, 57 | terserOptions: { 58 | output: { 59 | comments: false 60 | } 61 | } 62 | }) 63 | ] 64 | } 65 | : {}, 66 | resolve: { 67 | extensions: [".ts", ".js", ".json"] 68 | } 69 | }; 70 | }; 71 | -------------------------------------------------------------------------------- /webpack.example.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require("webpack"); 2 | const path = require("path"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | const SimpleProgressPlugin = require("webpack-simple-progress-plugin"); 5 | const CopyPlugin = require("copy-webpack-plugin"); 6 | const { CleanWebpackPlugin } = require("clean-webpack-plugin"); 7 | 8 | module.exports = options => { 9 | return { 10 | mode: "development", 11 | 12 | entry: { 13 | main: path.resolve("example/index.ts") 14 | }, 15 | 16 | output: { 17 | path: __dirname + "/dist", 18 | filename: "game.[hash].js" 19 | }, 20 | 21 | devtool: "source-map", 22 | 23 | module: { 24 | rules: [{ test: /\.ts$/, loader: "ts-loader" }] 25 | }, 26 | 27 | plugins: [ 28 | new CleanWebpackPlugin(), 29 | 30 | new HtmlWebpackPlugin({ 31 | template: path.resolve("static/index.html"), 32 | inject: false 33 | }), 34 | 35 | new CopyPlugin([{ from: "static", to: "." }]), 36 | 37 | new SimpleProgressPlugin() 38 | ], 39 | 40 | resolve: { 41 | extensions: [".ts", ".js", ".json"] 42 | }, 43 | 44 | devServer: { 45 | host: "0.0.0.0", 46 | contentBase: path.join(__dirname, "static"), 47 | hot: true, 48 | disableHostCheck: true, 49 | inline: false 50 | } 51 | }; 52 | }; 53 | --------------------------------------------------------------------------------