├── .github ├── stale.yml └── workflows │ ├── ci.yml │ └── update_dependencies.yml ├── .gitignore ├── .mergify.yml ├── .npmignore ├── .prettierignore ├── .prettierrc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── downstream_projects.json ├── examples ├── angular-cli │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── angular.json │ ├── cypress.json │ ├── cypress │ │ └── integration │ │ │ └── example_spec.js │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── about.component.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── continentList.component.ts │ │ │ ├── countryDetail.component.ts │ │ │ ├── countryList.component.ts │ │ │ ├── data.api.ts │ │ │ └── data.json │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.css │ │ ├── test.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.spec.json │ │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── angularjs-bower-script-tags │ ├── README.md │ ├── app │ │ ├── about.component.js │ │ ├── continentList.component.js │ │ ├── countryDetail.component.js │ │ ├── countryList.component.js │ │ ├── data.json │ │ ├── index.js │ │ └── router.config.js │ ├── bower.json │ ├── cypress.json │ ├── cypress │ │ └── integration │ │ │ └── example_spec.js │ ├── index.html │ ├── index.js │ ├── package.json │ └── styles.css ├── angularjs-npm-script-tags │ ├── README.md │ ├── app │ │ ├── about.component.js │ │ ├── continentList.component.js │ │ ├── countryDetail.component.js │ │ ├── countryList.component.js │ │ ├── data.json │ │ ├── index.js │ │ └── router.config.js │ ├── cypress.json │ ├── cypress │ │ └── integration │ │ │ └── example_spec.js │ ├── index.html │ ├── index.js │ ├── package.json │ └── styles.css ├── angularjs-webpack │ ├── README.md │ ├── app │ │ ├── about.component.js │ │ ├── app.module.js │ │ ├── continentList.component.js │ │ ├── countryDetail.component.js │ │ ├── countryList.component.js │ │ ├── data.api.js │ │ ├── data.json │ │ ├── index.js │ │ └── router.config.js │ ├── cypress.json │ ├── cypress │ │ └── integration │ │ │ └── example_spec.js │ ├── index.html │ ├── index.js │ ├── package.json │ ├── styles.css │ └── webpack.config.js └── create-react-app │ ├── README.md │ ├── cypress.json │ ├── cypress │ └── integration │ │ └── example_spec.js │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ └── src │ ├── About.jsx │ ├── App.css │ ├── App.jsx │ ├── ContinentList.jsx │ ├── CountryDetail.jsx │ ├── CountryList.jsx │ ├── data.api.js │ ├── data.json │ └── index.js ├── jest.config.js ├── karma.conf.js ├── package.json ├── rollup.config.js ├── src ├── DSRDataStore.ts ├── dsr.ts ├── index.ts └── interface.ts ├── test ├── deepStateRedirectSpec.ts ├── index.js └── util.ts ├── tsconfig.json └── yarn.lock /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 90 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 14 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - notstale 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: | 13 | This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. 14 | 15 | This does not mean that the issue is invalid. Valid issues may be reopened. 16 | 17 | Thank you for your contributions. 18 | # Comment to post when closing a stale issue. Set to `false` to disable 19 | closeComment: false 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: 'CI' 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | ci: 11 | needs: [test, downstream] 12 | runs-on: ubuntu-latest 13 | steps: 14 | - run: true 15 | test: 16 | name: yarn test 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v2 20 | - name: Install Dependencies 21 | run: yarn install --pure-lockfile 22 | - name: Check Peer Dependencies 23 | run: npx check-peer-dependencies 24 | - name: Run Tests 25 | run: yarn test 26 | 27 | downstream: 28 | name: Test downstream ${{ matrix.group }} projects 29 | runs-on: ubuntu-latest 30 | strategy: 31 | matrix: 32 | group: ['angular', 'angularjs', 'react'] 33 | steps: 34 | - uses: actions/checkout@v2 35 | - name: Prepare to Test Downstream Projects 36 | run: | 37 | npm config set scripts-prepend-node-path auto 38 | git config --global user.email uirouter@github.actions 39 | git config --global user.name uirouter_github_actions 40 | - name: Install Dependencies 41 | run: yarn install --pure-lockfile 42 | - name: Test Downstream Projects 43 | run: yarn test:downstream --group ${{ matrix.group }} 44 | -------------------------------------------------------------------------------- /.github/workflows/update_dependencies.yml: -------------------------------------------------------------------------------- 1 | # This workflow requires a personal access token for uirouterbot 2 | name: Weekly Dependency Bumps 3 | on: 4 | repository_dispatch: 5 | types: [update_dependencies] 6 | schedule: 7 | - cron: '0 21 * * 0' 8 | 9 | jobs: 10 | upgrade-dependencies: 11 | runs-on: ubuntu-latest 12 | name: Update dependencies 13 | strategy: 14 | matrix: 15 | excludes: [''] 16 | deptype: ['dependencies', 'devDependencies'] 17 | latest: [true] 18 | steps: 19 | - uses: actions/checkout@v2 20 | - run: | 21 | git config user.name uirouterbot 22 | git config user.password ${{ secrets.UIROUTERBOT_PAT }} 23 | git remote set-url origin $(git remote get-url origin | sed -e 's/ui-router/uirouterbot/') 24 | git fetch --unshallow -p origin 25 | - name: Update dependencies 26 | id: upgrade 27 | uses: ui-router/publish-scripts/actions/upgrade@actions-upgrade-v1.0.3 28 | with: 29 | excludes: ${{ matrix.excludes }} 30 | deptype: ${{ matrix.deptype }} 31 | latest: ${{ matrix.latest }} 32 | - name: Create Pull Request 33 | id: cpr 34 | if: ${{ steps.upgrade.outputs.upgrades != '' }} 35 | # the following hash is from https://github.com/peter-evans/create-pull-request/releases/tag/v2.7.0 36 | uses: peter-evans/create-pull-request@340e629d2f63059fb3e3f15437e92cfbc7acd85b 37 | with: 38 | token: ${{ secrets.UIROUTERBOT_PAT }} 39 | request-to-parent: true 40 | branch-suffix: 'random' 41 | commit-message: 'chore(package): Update ${{ steps.upgrade.outputs.upgradecount }} ${{ matrix.deptype }} to ${{ steps.upgrade.outputs.upgradestrategy }}' 42 | title: 'chore(package): Update ${{ steps.upgrade.outputs.upgradecount }} ${{ matrix.deptype }} to ${{ steps.upgrade.outputs.upgradestrategy }}' 43 | body: | 44 | chore(package): Update ${{ steps.upgrade.outputs.upgradecount }} ${{ matrix.deptype }} to ${{ steps.upgrade.outputs.upgradestrategy }} 45 | 46 | ``` 47 | ${{ steps.upgrade.outputs.upgrades }} 48 | ``` 49 | 50 | Auto-generated by [create-pull-request][1] 51 | 52 | [1]: https://github.com/peter-evans/create-pull-request 53 | - name: Apply Merge Label 54 | if: ${{ steps.cpr.outputs.pr_number != '' }} 55 | uses: actions/github-script@0.9.0 56 | with: 57 | github-token: ${{ secrets.UIROUTERBOT_PAT }} 58 | script: | 59 | await github.issues.addLabels({ 60 | owner: context.repo.owner, 61 | repo: context.repo.repo, 62 | issue_number: ${{ steps.cpr.outputs.pr_number }}, 63 | labels: ['ready to squash and merge'] 64 | }); 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # master only 2 | build 3 | bundles 4 | build_packages 5 | site 6 | yarn-error.log 7 | 8 | # common 9 | **/.* 10 | *~ 11 | node_modules 12 | bower_components 13 | lib 14 | lib-esm 15 | _bundles 16 | 17 | # webstorm files 18 | .idea 19 | idea-out 20 | *.iml 21 | *.ipr 22 | *.iws 23 | 24 | # generate doc to _doc; copy to proper gh-pages dir 25 | _doc 26 | 27 | !.github 28 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | pull_request_rules: 2 | - name: Auto Squash and Merge 3 | conditions: 4 | - base=master 5 | - status-success=ci 6 | - 'label=ready to squash and merge' 7 | actions: 8 | delete_head_branch: {} 9 | merge: 10 | method: squash 11 | strict: smart 12 | - name: Auto Rebase and Merge 13 | conditions: 14 | - base=master 15 | - status-success=ci 16 | - 'label=ready to rebase and merge' 17 | actions: 18 | delete_head_branch: {} 19 | merge: 20 | method: rebase 21 | strict: smart 22 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Any hidden files 2 | **/.* 3 | .* 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | src 9 | test 10 | scripts 11 | 12 | node_modules 13 | 14 | tslint.json 15 | tsconfig.json 16 | tsconfig.**.json 17 | webpack.config.js 18 | rollup.config.js 19 | karma.conf.js 20 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5", 4 | "printWidth": 120 5 | } 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.2.0 (2019-12-26) 2 | 3 | [Compare `@uirouter/dsr` versions 1.1.1 and 1.2.0](https://github.com/ui-router/dsr/compare/1.1.1...1.2.0) 4 | 5 | ### Bug Fixes 6 | 7 | - **params:** When performing DSR with param criteria, only consider the parameters listed in the dsr configuration block ([d073218](https://github.com/ui-router/dsr/commit/d073218)) 8 | 9 | ## 1.1.1 (2019-10-08) 10 | 11 | [Compare `@uirouter/dsr` versions 1.1.0 and 1.1.1](https://github.com/ui-router/dsr/compare/1.1.0...1.1.1) 12 | 13 | ### Bug Fixes 14 | 15 | - **examples:** update angular-cli example to uirouter/angular 4.x ([2c0388c](https://github.com/ui-router/dsr/commit/2c0388c)) 16 | - **package:** Change peerDependency on uirouter/core from '^5.0.1' to '>=5.0.1' ([d039187](https://github.com/ui-router/dsr/commit/d039187)) 17 | - **travis:** use service: xvfb instead of launching it manually. install libgconf debian package ([fb48a4a](https://github.com/ui-router/dsr/commit/fb48a4a)) 18 | 19 | # 1.1.0 (2019-01-16) 20 | 21 | [Compare `@uirouter/dsr` versions 1.0.3 and 1.1.0](https://github.com/ui-router/dsr/compare/1.0.3...1.1.0) 22 | 23 | ### Features 24 | 25 | - **dataSource:** Added pluggable dataSource ability and created LocalStorageDataSource ([1a934b4](https://github.com/ui-router/dsr/commit/1a934b4)), closes [#90](https://github.com/ui-router/dsr/issues/90) 26 | - **dataSource:** Create SessionStorageDataSource ([a26579c](https://github.com/ui-router/dsr/commit/a26579c)) 27 | 28 | ## 1.0.3 (2018-03-31) 29 | 30 | [Compare `@uirouter/dsr` versions 1.0.2 and 1.0.3](https://github.com/ui-router/dsr/compare/1.0.2...1.0.3) 31 | 32 | ### Bug Fixes 33 | 34 | - **typings:** Augment StateDeclaration using deep path ([#3](https://github.com/ui-router/dsr/issues/3)) ([e582bc3](https://github.com/ui-router/dsr/commit/e582bc3)), closes [#2](https://github.com/ui-router/dsr/issues/2) 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013-2015 The AngularUI Team, Karsten Sperling 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Deep State Redirect 2 | 3 | ### DSR for UI-Router 1.0  [![Build Status](https://github.com/ui-router/dsr/workflows/CI:%20Deep%20State%20Redirect%20for%20UIRouter/badge.svg)](https://github.com/ui-router/dsr/actions?query=workflow%3A%22CI%3A+Deep+State+Redirect+for+UIRouter%22) 4 | 5 | With Deep State Redirect, a parent state remembers whatever child state was last activated. 6 | When the user directly reactivates the parent state, they are redirected to the nested state (which was previously activated). 7 | 8 | ## Overview and Use Case 9 | 10 | Deep State Redirect (DSR) is a marker you can add to a state definition. 11 | 12 | When a child state of the DSR marked state is activated, UI-Router Extras remembers the child and its parameters. 13 | The most-recently-activate child is remembered no matter where the user navigates in the state tree. 14 | When the DSR marked state is directly activated, UI-Router Extras will redirect to the remembered child state and parameters. 15 | 16 | One use case for DSR is a tabbed application. 17 | Each tab might contain an application module. 18 | Each tabs' state is marked as deepStateRedirect. 19 | When the user navigates into the tab, and drills down to a substate, DSR will remember the substate. 20 | The user can then navigate to other tabs (or somewhere else completely). 21 | When they click the original tab again, it will transition to the remembered ehild state and parameters of that tab, making it appear that the tab was never destructed. 22 | 23 | Deep State Redirect can be used with StickyStates, or on its own. 24 | If used with a Sticky State, the states will be reactivated, and the DOM will be unchanged (as opposed to the states being re-entered and controllers re-initialized) 25 | 26 | ## Using 27 | 28 | See: http://christopherthielen.github.io/ui-router-extras/#/dsr 29 | 30 | TODO: Move docs here 31 | 32 | ### Using a custom DataStore 33 | 34 | By default DSR stores the most recent redirects in memory. 35 | Alternatively, you can store the redirects in Local Storage using 36 | [LocalStorageDataStore](https://github.com/ui-router/dsr/blob/master/src/DSRDataStore.ts) 37 | or create your own DataStore. 38 | 39 | When registering the DSRPlugin, pass an options object with a `dataStore` property, i.e.: 40 | 41 | ```js 42 | router.plugin(DSRPlugin, { dataStore: new LocalStorageDataStore() }); 43 | ``` 44 | 45 | ## Example Builds 46 | 47 | The [`/examples` directory](https://github.com/ui-router/dsr/tree/master/examples) contains example setups for: 48 | 49 | - Angular-CLI 50 | - AngularJS + bower + script tags 51 | - AngularJS + npm + script tags 52 | - AngularJS + webpack 53 | - Create-React-App 54 | -------------------------------------------------------------------------------- /downstream_projects.json: -------------------------------------------------------------------------------- 1 | { 2 | "angular": { 3 | "angular-cli": "./examples/angular-cli" 4 | }, 5 | "angularjs": { 6 | "angularjs-webpack": "./examples/angularjs-webpack" 7 | }, 8 | "react": { 9 | "create-react-app": "./examples/create-react-app" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/angular-cli/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /examples/angular-cli/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | 44 | -------------------------------------------------------------------------------- /examples/angular-cli/README.md: -------------------------------------------------------------------------------- 1 | # Angular-CLI 2 | 3 | Example showing sticky states installed in an Angular-CLI app. 4 | 5 | ## Running 6 | 7 | ``` 8 | npm install 9 | npm start 10 | ``` -------------------------------------------------------------------------------- /examples/angular-cli/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-cli": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "architect": { 11 | "build": { 12 | "builder": "@angular-devkit/build-angular:browser", 13 | "options": { 14 | "outputPath": "dist", 15 | "index": "src/index.html", 16 | "main": "src/main.ts", 17 | "tsConfig": "src/tsconfig.app.json", 18 | "polyfills": "src/polyfills.ts", 19 | "assets": ["src/assets", "src/favicon.ico"], 20 | "styles": ["src/styles.css"], 21 | "scripts": [] 22 | }, 23 | "configurations": { 24 | "production": { 25 | "optimization": true, 26 | "outputHashing": "all", 27 | "sourceMap": false, 28 | "extractCss": true, 29 | "namedChunks": false, 30 | "aot": true, 31 | "extractLicenses": true, 32 | "vendorChunk": false, 33 | "buildOptimizer": true, 34 | "fileReplacements": [ 35 | { 36 | "replace": "src/environments/environment.ts", 37 | "with": "src/environments/environment.prod.ts" 38 | } 39 | ] 40 | } 41 | } 42 | }, 43 | "serve": { 44 | "builder": "@angular-devkit/build-angular:dev-server", 45 | "options": { 46 | "browserTarget": "angular-cli:build" 47 | }, 48 | "configurations": { 49 | "production": { 50 | "browserTarget": "angular-cli:build:production" 51 | } 52 | } 53 | }, 54 | "extract-i18n": { 55 | "builder": "@angular-devkit/build-angular:extract-i18n", 56 | "options": { 57 | "browserTarget": "angular-cli:build" 58 | } 59 | }, 60 | "test": { 61 | "builder": "@angular-devkit/build-angular:karma", 62 | "options": { 63 | "main": "src/test.ts", 64 | "karmaConfig": "./karma.conf.js", 65 | "polyfills": "src/polyfills.ts", 66 | "tsConfig": "src/tsconfig.spec.json", 67 | "scripts": [], 68 | "styles": ["src/styles.css"], 69 | "assets": ["src/assets", "src/favicon.ico"] 70 | } 71 | }, 72 | "lint": { 73 | "builder": "@angular-devkit/build-angular:tslint", 74 | "options": { 75 | "tsConfig": ["src/tsconfig.app.json", "src/tsconfig.spec.json"], 76 | "exclude": ["**/node_modules/**"] 77 | } 78 | } 79 | } 80 | }, 81 | "angular-cli-e2e": { 82 | "root": "e2e", 83 | "sourceRoot": "e2e", 84 | "projectType": "application", 85 | "architect": { 86 | "e2e": { 87 | "builder": "@angular-devkit/build-angular:protractor", 88 | "options": { 89 | "protractorConfig": "./protractor.conf.js", 90 | "devServerTarget": "angular-cli:serve" 91 | } 92 | }, 93 | "lint": { 94 | "builder": "@angular-devkit/build-angular:tslint", 95 | "options": { 96 | "tsConfig": ["e2e/tsconfig.e2e.json"], 97 | "exclude": ["**/node_modules/**"] 98 | } 99 | } 100 | } 101 | } 102 | }, 103 | "defaultProject": "angular-cli", 104 | "schematics": { 105 | "@schematics/angular:component": { 106 | "prefix": "app", 107 | "styleext": "css" 108 | }, 109 | "@schematics/angular:directive": { 110 | "prefix": "app" 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /examples/angular-cli/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:4000", 3 | "video": false 4 | } 5 | -------------------------------------------------------------------------------- /examples/angular-cli/cypress/integration/example_spec.js: -------------------------------------------------------------------------------- 1 | describe('example app', () => { 2 | it('loads', () => { 3 | cy.visit(''); 4 | }); 5 | 6 | it('renders links', () => { 7 | cy.visit('/'); 8 | cy.get('a').contains('about'); 9 | cy.get('a').contains('continentlist'); 10 | }); 11 | 12 | it('renders about by default', () => { 13 | cy.visit('/'); 14 | cy.contains('This is a trivial Deep State Redirect example app'); 15 | }); 16 | 17 | it('can navigate to continentlist', () => { 18 | cy.visit(''); 19 | cy 20 | .get('a') 21 | .contains('continentlist') 22 | .click(); 23 | 24 | cy.contains('Africa'); 25 | cy.contains('America'); 26 | cy.contains('Oceania'); 27 | }); 28 | 29 | it('can navigate to belize', () => { 30 | cy.visit(''); 31 | cy 32 | .get('a') 33 | .contains('continentlist') 34 | .click(); 35 | cy 36 | .get('a') 37 | .contains('America') 38 | .click(); 39 | cy 40 | .get('a') 41 | .contains('Belize') 42 | .click(); 43 | cy.get('h3').contains('Belize'); 44 | }); 45 | 46 | it('can navigate to belize and back', () => { 47 | cy.visit(''); 48 | cy 49 | .get('a') 50 | .contains('continentlist') 51 | .click(); 52 | cy 53 | .get('a') 54 | .contains('America') 55 | .click(); 56 | cy.url().should('include', '/America'); 57 | 58 | cy 59 | .get('a') 60 | .contains('Belize') 61 | .click(); 62 | cy.get('h3').contains('Belize'); 63 | cy.url().should('include', '/America/Belize'); 64 | 65 | cy 66 | .get('a') 67 | .contains('about') 68 | .click(); 69 | cy.contains('This is a trivial Deep State Redirect example app'); 70 | }); 71 | 72 | it('dsr sends you back to belize', () => { 73 | cy.visit(''); 74 | cy 75 | .get('a') 76 | .contains('continentlist') 77 | .click(); 78 | cy 79 | .get('a') 80 | .contains('America') 81 | .click(); 82 | cy.url().should('include', '/America'); 83 | 84 | cy 85 | .get('a') 86 | .contains('Belize') 87 | .click(); 88 | cy.url().should('include', '/America/Belize'); 89 | cy.get('h3').contains('Belize'); 90 | 91 | cy 92 | .get('a') 93 | .contains('about') 94 | .click(); 95 | cy.url().should('include', '/about'); 96 | cy.contains('This is a trivial Deep State Redirect example app'); 97 | 98 | cy 99 | .get('a') 100 | .contains('continentlist') 101 | .click(); 102 | cy.url().should('include', '/America/Belize'); 103 | cy.get('h3').contains('Belize'); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /examples/angular-cli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-cli", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build --prod", 9 | "test": "npm run build && cypress-runner run --path dist", 10 | "test:open": "npm run build && cypress-runner open --path dist", 11 | "lint": "ng lint", 12 | "e2e": "ng e2e" 13 | }, 14 | "private": true, 15 | "dependencies": { 16 | "@angular/animations": "^7.2.0", 17 | "@angular/common": "^7.2.0", 18 | "@angular/compiler": "^7.2.0", 19 | "@angular/core": "^7.2.0", 20 | "@angular/forms": "^7.2.0", 21 | "@angular/http": "^7.2.0", 22 | "@angular/platform-browser": "^7.2.0", 23 | "@angular/platform-browser-dynamic": "^7.2.0", 24 | "@angular/router": "^7.2.0", 25 | "@uirouter/angular": "^4.0.0", 26 | "@uirouter/dsr": "^1.0.2", 27 | "@uirouter/visualizer": "^6.0.0", 28 | "core-js": "^2.4.1", 29 | "rxjs": "^6.3.3", 30 | "tslib": "^1.9.0", 31 | "zone.js": "^0.8.14", 32 | "rxjs-compat": "^6.0.0-rc.0" 33 | }, 34 | "devDependencies": { 35 | "@angular-devkit/build-angular": "~0.12.0", 36 | "@angular/cli": "^7.2.1", 37 | "@angular/compiler-cli": "^7.2.0", 38 | "@angular/language-service": "^7.2.0", 39 | "@types/jasmine": "~2.8.6", 40 | "@types/jasminewd2": "~2.0.2", 41 | "@types/node": "~9.6.1", 42 | "@uirouter/cypress-runner": "^1.0.2", 43 | "codelyzer": "^4.0.1", 44 | "jasmine-core": "~3.1.0", 45 | "jasmine-spec-reporter": "~4.2.1", 46 | "karma": "~2.0.0", 47 | "karma-chrome-launcher": "~2.2.0", 48 | "karma-cli": "~1.0.1", 49 | "karma-coverage-istanbul-reporter": "^1.2.1", 50 | "karma-jasmine": "~1.1.0", 51 | "karma-jasmine-html-reporter": "^1.0.0", 52 | "protractor": "~5.3.0", 53 | "ts-node": "~5.0.1", 54 | "tslint": "~5.9.1", 55 | "typescript": "~3.2.2" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /examples/angular-cli/src/app/about.component.ts: -------------------------------------------------------------------------------- 1 | import { Input, Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'generic-cmp', 5 | template: ` 6 |

This is a trivial Deep State Redirect example app

7 |
    8 |
  1. Active the continentlist state
  2. 9 |
  3. Select a continent
  4. 10 |
  5. Select a country
  6. 11 |
  7. Reactivate this state (about)
  8. 12 |
  9. 13 | Active the continents state again.
    14 | You are redirected to the previously active substate of continentlist (including parameters).
    15 | You should see the country you chose in the previous step. 16 |
  10. 17 |
18 | `, 19 | }) 20 | export class AboutComponent { 21 | } 22 | -------------------------------------------------------------------------------- /examples/angular-cli/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { StateService } from '@uirouter/core'; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | template: ` 7 | about 8 | continentlist 9 | 10 | 11 | `, 12 | styles: [` 13 | .active { font-weight: bold } 14 | `] 15 | }) 16 | export class AppComponent { 17 | constructor(public $state: StateService) { 18 | 19 | } 20 | isActive(stateName: string) { 21 | return this.$state.includes(stateName) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/angular-cli/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { BrowserModule } from '@angular/platform-browser'; 3 | import { FormsModule } from '@angular/forms'; 4 | 5 | import { UIRouterModule } from '@uirouter/angular'; 6 | import { UIRouter } from '@uirouter/core'; 7 | import { DSRPlugin } from '@uirouter/dsr'; 8 | import { Visualizer } from '@uirouter/visualizer'; 9 | 10 | import { AppComponent } from './app.component'; 11 | import { CountryDetailComponent } from './countryDetail.component'; 12 | import { CountryListComponent } from './countryList.component'; 13 | import { getContinents, getCountries } from './data.api'; 14 | import { ContinentListComponent } from './continentList.component'; 15 | import { AboutComponent } from './about.component'; 16 | 17 | export const states = [ 18 | { 19 | name: 'continentlist', 20 | url: '/continents', 21 | dsr: true, 22 | component: ContinentListComponent, 23 | resolve: { 24 | 'continents': () => getContinents() }, 25 | }, 26 | 27 | { 28 | name: 'continentlist.countrylist', 29 | url: '/:continent', 30 | component: CountryListComponent, 31 | resolve: { 32 | 'countries': ['$transition$', ($transition$) => getCountries($transition$.params().continent)], 33 | }, 34 | }, 35 | 36 | { 37 | name: 'continentlist.countrylist.countrydetail', 38 | url: '/:country', 39 | component: CountryDetailComponent, 40 | resolve: { 41 | 'country': ['$transition$', ($transition$) => $transition$.params().country], 42 | }, 43 | }, 44 | 45 | { 46 | name: 'about', 47 | url: '/about', 48 | component: AboutComponent, 49 | } 50 | ]; 51 | 52 | export function configFn(router: UIRouter) { 53 | states.forEach(state => router.stateRegistry.register(state)); 54 | router.urlService.rules.initial({ state: 'about' }); 55 | router.plugin(DSRPlugin); 56 | router.plugin(Visualizer); 57 | } 58 | 59 | @NgModule({ 60 | declarations: [ 61 | AboutComponent, 62 | AppComponent, 63 | ContinentListComponent, 64 | CountryDetailComponent, 65 | CountryListComponent, 66 | ], 67 | entryComponents: [ 68 | AboutComponent, 69 | AppComponent, 70 | ContinentListComponent, 71 | CountryDetailComponent, 72 | CountryListComponent, 73 | ], 74 | imports: [ 75 | BrowserModule, 76 | FormsModule, 77 | UIRouterModule.forRoot({ 78 | config: configFn, 79 | }) 80 | ], 81 | bootstrap: [AppComponent] 82 | }) 83 | export class AppModule { } 84 | -------------------------------------------------------------------------------- /examples/angular-cli/src/app/continentList.component.ts: -------------------------------------------------------------------------------- 1 | import { Input, Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'continent-list-cmp', 5 | template: ` 6 |

Continents

7 | 8 | 9 | {{ continent }} 10 | 11 | 12 | 13 | `, 14 | }) 15 | export class ContinentListComponent { 16 | @Input() continents: string[]; 17 | } 18 | -------------------------------------------------------------------------------- /examples/angular-cli/src/app/countryDetail.component.ts: -------------------------------------------------------------------------------- 1 | import { Input, Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'country-detail-cmp', 5 | template: ` 6 |

{{ country }}

7 |
8 | 9 |
10 | `, 11 | }) 12 | export class CountryDetailComponent { 13 | @Input() country: string; 14 | 15 | imageSrc() { 16 | if (!this.country) { return ''; } 17 | const prefix = 'http://www.randomlists.com/img/national-flags/'; 18 | const imageName = this.country.toLowerCase().replace(/ /g, '_'); 19 | return `${prefix}${imageName}.gif`; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /examples/angular-cli/src/app/countryList.component.ts: -------------------------------------------------------------------------------- 1 | import { Input, Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'country-list-cmp', 5 | template: ` 6 | 7 | 8 |
9 | 14 | {{ country }} 15 | 16 |
17 | 18 | `, 19 | styles: [` 20 | .container { 21 | display: flex; 22 | flex-flow: row wrap; 23 | } 24 | .container > * { 25 | border: 1px solid; 26 | padding: 0.5em; 27 | margin: 0.5em; 28 | flex: 1 1 75px; 29 | } 30 | .container > a.active { 31 | background: lightgray; 32 | } 33 | `] 34 | }) 35 | export class CountryListComponent { 36 | @Input() countries: string[]; 37 | } 38 | -------------------------------------------------------------------------------- /examples/angular-cli/src/app/data.api.ts: -------------------------------------------------------------------------------- 1 | declare var require; 2 | 3 | function getContinents(): Promise { 4 | return Promise.resolve(require('./data.json')) 5 | .then(countries => countries.map(country => country.continent)) 6 | .then(continents => continents.reduce((acc, continent) => acc.includes(continent) ? acc : acc.concat(continent), [])) 7 | } 8 | 9 | function getCountries(continent: string): Promise { 10 | return Promise.resolve(require('./data.json')) 11 | .then(countries => countries.filter(country => country.continent === continent)) 12 | .then(countries => countries.map(country => country.name)); 13 | } 14 | 15 | export { getContinents, getCountries }; 16 | -------------------------------------------------------------------------------- /examples/angular-cli/src/app/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Afghanistan", 4 | "continent": "Asia" 5 | }, 6 | { 7 | "name": "Albania", 8 | "continent": "Europe" 9 | }, 10 | { 11 | "name": "Algeria", 12 | "continent": "Africa" 13 | }, 14 | { 15 | "name": "Andorra", 16 | "continent": "Europe" 17 | }, 18 | { 19 | "name": "Angola", 20 | "continent": "Africa" 21 | }, 22 | { 23 | "name": "Antigua and Barbuda", 24 | "continent": "America" 25 | }, 26 | { 27 | "name": "Argentina", 28 | "continent": "America" 29 | }, 30 | { 31 | "name": "Armenia", 32 | "continent": "Asia" 33 | }, 34 | { 35 | "name": "Australia", 36 | "continent": "Oceania" 37 | }, 38 | { 39 | "name": "Austria", 40 | "continent": "Europe" 41 | }, 42 | { 43 | "name": "Azerbaijan", 44 | "continent": "Asia" 45 | }, 46 | { 47 | "name": "Bahamas", 48 | "continent": "America" 49 | }, 50 | { 51 | "name": "Bahrain", 52 | "continent": "Asia" 53 | }, 54 | { 55 | "name": "Bangladesh", 56 | "continent": "Asia" 57 | }, 58 | { 59 | "name": "Barbados", 60 | "continent": "America" 61 | }, 62 | { 63 | "name": "Belarus", 64 | "continent": "Europe" 65 | }, 66 | { 67 | "name": "Belgium", 68 | "continent": "Europe" 69 | }, 70 | { 71 | "name": "Belize", 72 | "continent": "America" 73 | }, 74 | { 75 | "name": "Benin", 76 | "continent": "Africa" 77 | }, 78 | { 79 | "name": "Bhutan", 80 | "continent": "Asia" 81 | }, 82 | { 83 | "name": "Bolivia", 84 | "continent": "America" 85 | }, 86 | { 87 | "name": "Bosnia and Herzegovina", 88 | "continent": "Europe" 89 | }, 90 | { 91 | "name": "Botswana", 92 | "continent": "Africa" 93 | }, 94 | { 95 | "name": "Brazil", 96 | "continent": "America" 97 | }, 98 | { 99 | "name": "Brunei", 100 | "continent": "Asia" 101 | }, 102 | { 103 | "name": "Bulgaria", 104 | "continent": "Europe" 105 | }, 106 | { 107 | "name": "Burkina Faso", 108 | "continent": "Africa" 109 | }, 110 | { 111 | "name": "Myanmar", 112 | "continent": "Asia" 113 | }, 114 | { 115 | "name": "Burundi", 116 | "continent": "Africa" 117 | }, 118 | { 119 | "name": "Cambodia", 120 | "continent": "Asia" 121 | }, 122 | { 123 | "name": "Cameroon", 124 | "continent": "Africa" 125 | }, 126 | { 127 | "name": "Canada", 128 | "continent": "America" 129 | }, 130 | { 131 | "name": "Cape Verde", 132 | "continent": "Africa" 133 | }, 134 | { 135 | "name": "Central African Republic", 136 | "continent": "Africa" 137 | }, 138 | { 139 | "name": "Chad", 140 | "continent": "Africa" 141 | }, 142 | { 143 | "name": "Chile", 144 | "continent": "America" 145 | }, 146 | { 147 | "name": "China", 148 | "continent": "Asia" 149 | }, 150 | { 151 | "name": "Colombia", 152 | "continent": "America" 153 | }, 154 | { 155 | "name": "Comoros", 156 | "continent": "Africa" 157 | }, 158 | { 159 | "name": "Congo", 160 | "continent": "Africa" 161 | }, 162 | { 163 | "name": "Costa Rica", 164 | "continent": "America" 165 | }, 166 | { 167 | "name": "Croatia", 168 | "continent": "Europe" 169 | }, 170 | { 171 | "name": "Cuba", 172 | "continent": "America" 173 | }, 174 | { 175 | "name": "Cyprus", 176 | "continent": "Europe" 177 | }, 178 | { 179 | "name": "Czech Republic", 180 | "continent": "Europe" 181 | }, 182 | { 183 | "name": "Denmark", 184 | "continent": "Europe" 185 | }, 186 | { 187 | "name": "Djibouti", 188 | "continent": "Africa" 189 | }, 190 | { 191 | "name": "Dominica", 192 | "continent": "America" 193 | }, 194 | { 195 | "name": "Dominican Republic", 196 | "continent": "America" 197 | }, 198 | { 199 | "name": "East Timor", 200 | "continent": "Asia" 201 | }, 202 | { 203 | "name": "Ecuador", 204 | "continent": "America" 205 | }, 206 | { 207 | "name": "Egypt", 208 | "continent": "Africa" 209 | }, 210 | { 211 | "name": "El Salvador", 212 | "continent": "America" 213 | }, 214 | { 215 | "name": "England", 216 | "continent": "Europe" 217 | }, 218 | { 219 | "name": "Equatorial Guinea", 220 | "continent": "Africa" 221 | }, 222 | { 223 | "name": "Eritrea", 224 | "continent": "Africa" 225 | }, 226 | { 227 | "name": "Estonia", 228 | "continent": "Europe" 229 | }, 230 | { 231 | "name": "Ethiopia", 232 | "continent": "Africa" 233 | }, 234 | { 235 | "name": "Fiji", 236 | "continent": "Oceania" 237 | }, 238 | { 239 | "name": "Finland", 240 | "continent": "Europe" 241 | }, 242 | { 243 | "name": "France", 244 | "continent": "Europe" 245 | }, 246 | { 247 | "name": "Gabon", 248 | "continent": "Africa" 249 | }, 250 | { 251 | "name": "Gambia", 252 | "continent": "Africa" 253 | }, 254 | { 255 | "name": "Georgia", 256 | "continent": "Asia" 257 | }, 258 | { 259 | "name": "Germany", 260 | "continent": "Europe" 261 | }, 262 | { 263 | "name": "Ghana", 264 | "continent": "Africa" 265 | }, 266 | { 267 | "name": "Greece", 268 | "continent": "Europe" 269 | }, 270 | { 271 | "name": "Grenada", 272 | "continent": "America" 273 | }, 274 | { 275 | "name": "Guatemala", 276 | "continent": "America" 277 | }, 278 | { 279 | "name": "Guinea", 280 | "continent": "Africa" 281 | }, 282 | { 283 | "name": "Guinea-Bissau", 284 | "continent": "Africa" 285 | }, 286 | { 287 | "name": "Guyana", 288 | "continent": "America" 289 | }, 290 | { 291 | "name": "Haiti", 292 | "continent": "America" 293 | }, 294 | { 295 | "name": "Honduras", 296 | "continent": "America" 297 | }, 298 | { 299 | "name": "Hong Kong", 300 | "continent": "Asia" 301 | }, 302 | { 303 | "name": "Hungary", 304 | "continent": "Europe" 305 | }, 306 | { 307 | "name": "Iceland", 308 | "continent": "Europe" 309 | }, 310 | { 311 | "name": "India", 312 | "continent": "Asia" 313 | }, 314 | { 315 | "name": "Indonesia", 316 | "continent": "Asia" 317 | }, 318 | { 319 | "name": "Iran", 320 | "continent": "Asia" 321 | }, 322 | { 323 | "name": "Iraq", 324 | "continent": "Asia" 325 | }, 326 | { 327 | "name": "Ireland", 328 | "continent": "Europe" 329 | }, 330 | { 331 | "name": "Isle of Man", 332 | "continent": "Europe" 333 | }, 334 | { 335 | "name": "Israel", 336 | "continent": "Asia" 337 | }, 338 | { 339 | "name": "Italy", 340 | "continent": "Europe" 341 | }, 342 | { 343 | "name": "Jamaica", 344 | "continent": "America" 345 | }, 346 | { 347 | "name": "Japan", 348 | "continent": "Asia" 349 | }, 350 | { 351 | "name": "Jordan", 352 | "continent": "Asia" 353 | }, 354 | { 355 | "name": "Kazakhstan", 356 | "continent": "Asia" 357 | }, 358 | { 359 | "name": "Kenya", 360 | "continent": "Africa" 361 | }, 362 | { 363 | "name": "Kiribati", 364 | "continent": "Oceania" 365 | }, 366 | { 367 | "name": "North Korea", 368 | "continent": "Asia" 369 | }, 370 | { 371 | "name": "South Korea", 372 | "continent": "Asia" 373 | }, 374 | { 375 | "name": "Kosovo", 376 | "continent": "Europe" 377 | }, 378 | { 379 | "name": "Kuwait", 380 | "continent": "Asia" 381 | }, 382 | { 383 | "name": "Kyrgyzstan", 384 | "continent": "Asia" 385 | }, 386 | { 387 | "name": "Laos", 388 | "continent": "Asia" 389 | }, 390 | { 391 | "name": "Latvia", 392 | "continent": "Europe" 393 | }, 394 | { 395 | "name": "Lebanon", 396 | "continent": "Asia" 397 | }, 398 | { 399 | "name": "Lesotho", 400 | "continent": "Africa" 401 | }, 402 | { 403 | "name": "Liberia", 404 | "continent": "Africa" 405 | }, 406 | { 407 | "name": "Libya", 408 | "continent": "Africa" 409 | }, 410 | { 411 | "name": "Liechtenstein", 412 | "continent": "Europe" 413 | }, 414 | { 415 | "name": "Lithuania", 416 | "continent": "Europe" 417 | }, 418 | { 419 | "name": "Luxembourg", 420 | "continent": "Europe" 421 | }, 422 | { 423 | "name": "Macau", 424 | "continent": "Asia" 425 | }, 426 | { 427 | "name": "Macedonia", 428 | "continent": "Europe" 429 | }, 430 | { 431 | "name": "Madagascar", 432 | "continent": "Africa" 433 | }, 434 | { 435 | "name": "Malawi", 436 | "continent": "Africa" 437 | }, 438 | { 439 | "name": "Malaysia", 440 | "continent": "Asia" 441 | }, 442 | { 443 | "name": "Maldives", 444 | "continent": "Asia" 445 | }, 446 | { 447 | "name": "Mali", 448 | "continent": "Africa" 449 | }, 450 | { 451 | "name": "Malta", 452 | "continent": "Europe" 453 | }, 454 | { 455 | "name": "Marshall Islands", 456 | "continent": "Oceania" 457 | }, 458 | { 459 | "name": "Mauritania", 460 | "continent": "Africa" 461 | }, 462 | { 463 | "name": "Mauritius", 464 | "continent": "Africa" 465 | }, 466 | { 467 | "name": "Mexico", 468 | "continent": "America" 469 | }, 470 | { 471 | "name": "Micronesia", 472 | "continent": "Oceania" 473 | }, 474 | { 475 | "name": "Moldova", 476 | "continent": "Europe" 477 | }, 478 | { 479 | "name": "Monaco", 480 | "continent": "Europe" 481 | }, 482 | { 483 | "name": "Mongolia", 484 | "continent": "Asia" 485 | }, 486 | { 487 | "name": "Montenegro", 488 | "continent": "Europe" 489 | }, 490 | { 491 | "name": "Morocco", 492 | "continent": "Africa" 493 | }, 494 | { 495 | "name": "Mozambique", 496 | "continent": "Africa" 497 | }, 498 | { 499 | "name": "Namibia", 500 | "continent": "Africa" 501 | }, 502 | { 503 | "name": "Nauru", 504 | "continent": "Oceania" 505 | }, 506 | { 507 | "name": "Nepal", 508 | "continent": "Asia" 509 | }, 510 | { 511 | "name": "Netherlands", 512 | "continent": "Europe" 513 | }, 514 | { 515 | "name": "New Zealand", 516 | "continent": "Oceania" 517 | }, 518 | { 519 | "name": "Nicaragua", 520 | "continent": "America" 521 | }, 522 | { 523 | "name": "Niger", 524 | "continent": "Africa" 525 | }, 526 | { 527 | "name": "Nigeria", 528 | "continent": "Africa" 529 | }, 530 | { 531 | "name": "Norway", 532 | "continent": "Europe" 533 | }, 534 | { 535 | "name": "Oman", 536 | "continent": "Asia" 537 | }, 538 | { 539 | "name": "Pakistan", 540 | "continent": "Asia" 541 | }, 542 | { 543 | "name": "Palau", 544 | "continent": "Oceania" 545 | }, 546 | { 547 | "name": "Panama", 548 | "continent": "America" 549 | }, 550 | { 551 | "name": "Papua New Guinea", 552 | "continent": "Oceania" 553 | }, 554 | { 555 | "name": "Paraguay", 556 | "continent": "America" 557 | }, 558 | { 559 | "name": "Peru", 560 | "continent": "America" 561 | }, 562 | { 563 | "name": "Philippines", 564 | "continent": "Asia" 565 | }, 566 | { 567 | "name": "Poland", 568 | "continent": "Europe" 569 | }, 570 | { 571 | "name": "Portugal", 572 | "continent": "Europe" 573 | }, 574 | { 575 | "name": "Puerto Rico", 576 | "continent": "America" 577 | }, 578 | { 579 | "name": "Qatar", 580 | "continent": "Asia" 581 | }, 582 | { 583 | "name": "Romania", 584 | "continent": "Europe" 585 | }, 586 | { 587 | "name": "Russia", 588 | "continent": "Europe" 589 | }, 590 | { 591 | "name": "Rwanda", 592 | "continent": "Africa" 593 | }, 594 | { 595 | "name": "Saint Kitts and Nevis", 596 | "continent": "America" 597 | }, 598 | { 599 | "name": "Saint Lucia", 600 | "continent": "America" 601 | }, 602 | { 603 | "name": "Saint Vincent and the Grenadines", 604 | "continent": "America" 605 | }, 606 | { 607 | "name": "Samoa", 608 | "continent": "Oceania" 609 | }, 610 | { 611 | "name": "San Marino", 612 | "continent": "Europe" 613 | }, 614 | { 615 | "name": "Saudi Arabia", 616 | "continent": "Asia" 617 | }, 618 | { 619 | "name": "Scotland", 620 | "continent": "Europe" 621 | }, 622 | { 623 | "name": "Senegal", 624 | "continent": "Africa" 625 | }, 626 | { 627 | "name": "Serbia", 628 | "continent": "Europe" 629 | }, 630 | { 631 | "name": "Seychelles", 632 | "continent": "Africa" 633 | }, 634 | { 635 | "name": "Sierra Leone", 636 | "continent": "Africa" 637 | }, 638 | { 639 | "name": "Singapore", 640 | "continent": "Asia" 641 | }, 642 | { 643 | "name": "Slovakia", 644 | "continent": "Europe" 645 | }, 646 | { 647 | "name": "Slovenia", 648 | "continent": "Europe" 649 | }, 650 | { 651 | "name": "Solomon Islands", 652 | "continent": "Oceania" 653 | }, 654 | { 655 | "name": "Somalia", 656 | "continent": "Africa" 657 | }, 658 | { 659 | "name": "South Africa", 660 | "continent": "Africa" 661 | }, 662 | { 663 | "name": "Spain", 664 | "continent": "Europe" 665 | }, 666 | { 667 | "name": "Sri Lanka", 668 | "continent": "Asia" 669 | }, 670 | { 671 | "name": "Sudan", 672 | "continent": "Africa" 673 | }, 674 | { 675 | "name": "Suriname", 676 | "continent": "America" 677 | }, 678 | { 679 | "name": "Swaziland", 680 | "continent": "Africa" 681 | }, 682 | { 683 | "name": "Sweden", 684 | "continent": "Europe" 685 | }, 686 | { 687 | "name": "Switzerland", 688 | "continent": "Europe" 689 | }, 690 | { 691 | "name": "Syria", 692 | "continent": "Asia" 693 | }, 694 | { 695 | "name": "Taiwan", 696 | "continent": "Asia" 697 | }, 698 | { 699 | "name": "Tajikistan", 700 | "continent": "Asia" 701 | }, 702 | { 703 | "name": "Tanzania", 704 | "continent": "Africa" 705 | }, 706 | { 707 | "name": "Thailand", 708 | "continent": "Asia" 709 | }, 710 | { 711 | "name": "Togo", 712 | "continent": "Africa" 713 | }, 714 | { 715 | "name": "Tonga", 716 | "continent": "Oceania" 717 | }, 718 | { 719 | "name": "Trinidad and Tobago", 720 | "continent": "America" 721 | }, 722 | { 723 | "name": "Tunisia", 724 | "continent": "Africa" 725 | }, 726 | { 727 | "name": "Turkey", 728 | "continent": "Asia" 729 | }, 730 | { 731 | "name": "Turkmenistan", 732 | "continent": "Asia" 733 | }, 734 | { 735 | "name": "Tuvalu", 736 | "continent": "Oceania" 737 | }, 738 | { 739 | "name": "Uganda", 740 | "continent": "Africa" 741 | }, 742 | { 743 | "name": "Ukraine", 744 | "continent": "Europe" 745 | }, 746 | { 747 | "name": "United Arab Emirates", 748 | "continent": "Asia" 749 | }, 750 | { 751 | "name": "United Kingdom", 752 | "continent": "Europe" 753 | }, 754 | { 755 | "name": "United States of America", 756 | "continent": "America" 757 | }, 758 | { 759 | "name": "Uruguay", 760 | "continent": "America" 761 | }, 762 | { 763 | "name": "USSR", 764 | "continent": "Europe" 765 | }, 766 | { 767 | "name": "Uzbekistan", 768 | "continent": "Asia" 769 | }, 770 | { 771 | "name": "Vanuatu", 772 | "continent": "Oceania" 773 | }, 774 | { 775 | "name": "Vatican City", 776 | "continent": "Europe" 777 | }, 778 | { 779 | "name": "Venezuela", 780 | "continent": "America" 781 | }, 782 | { 783 | "name": "Vietnam", 784 | "continent": "Asia" 785 | }, 786 | { 787 | "name": "Wales", 788 | "continent": "Europe" 789 | }, 790 | { 791 | "name": "Yemen", 792 | "continent": "Asia" 793 | }, 794 | { 795 | "name": "Zambia", 796 | "continent": "Africa" 797 | }, 798 | { 799 | "name": "Zimbabwe", 800 | "continent": "Africa" 801 | } 802 | ] 803 | -------------------------------------------------------------------------------- /examples/angular-cli/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /examples/angular-cli/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /examples/angular-cli/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ui-router/dsr/faf4ac097655375f2d1804ef706b3836b73597d3/examples/angular-cli/src/favicon.ico -------------------------------------------------------------------------------- /examples/angular-cli/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AngularCli 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/angular-cli/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.log(err)); 13 | -------------------------------------------------------------------------------- /examples/angular-cli/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | /** Evergreen browsers require these. **/ 44 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 45 | 46 | /** 47 | * Required to support Web Animations `@angular/platform-browser/animations`. 48 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 49 | **/ 50 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 51 | 52 | /*************************************************************************************************** 53 | * Zone JS is required by default for Angular itself. 54 | */ 55 | import 'zone.js/dist/zone'; // Included with Angular CLI. 56 | 57 | /*************************************************************************************************** 58 | * APPLICATION IMPORTS 59 | */ 60 | -------------------------------------------------------------------------------- /examples/angular-cli/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | 3 | .active { 4 | font-weight: bold; 5 | } 6 | -------------------------------------------------------------------------------- /examples/angular-cli/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare const __karma__: any; 17 | declare const require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /examples/angular-cli/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/angular-cli/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["jasmine", "node"] 9 | }, 10 | "files": ["test.ts", "polyfills.ts"], 11 | "include": ["**/*.spec.ts", "**/*.d.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /examples/angular-cli/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /examples/angular-cli/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "importHelpers": true, 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": ["node_modules/@types"], 13 | "lib": ["es2017", "dom"], 14 | "module": "es2015", 15 | "baseUrl": "./" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/angular-cli/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["node_modules/codelyzer"], 3 | "rules": { 4 | "arrow-return-shorthand": true, 5 | "callable-types": true, 6 | "class-name": true, 7 | "comment-format": [true, "check-space"], 8 | "curly": true, 9 | "deprecation": { 10 | "severity": "warn" 11 | }, 12 | "eofline": true, 13 | "forin": true, 14 | "import-blacklist": [true, "rxjs/Rx"], 15 | "import-spacing": true, 16 | "indent": [true, "spaces"], 17 | "interface-over-type-literal": true, 18 | "label-position": true, 19 | "max-line-length": [true, 140], 20 | "member-access": false, 21 | "member-ordering": [ 22 | true, 23 | { 24 | "order": ["static-field", "instance-field", "static-method", "instance-method"] 25 | } 26 | ], 27 | "no-arg": true, 28 | "no-bitwise": true, 29 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], 30 | "no-construct": true, 31 | "no-debugger": true, 32 | "no-duplicate-super": true, 33 | "no-empty": false, 34 | "no-empty-interface": true, 35 | "no-eval": true, 36 | "no-inferrable-types": [true, "ignore-params"], 37 | "no-misused-new": true, 38 | "no-non-null-assertion": true, 39 | "no-shadowed-variable": true, 40 | "no-string-literal": false, 41 | "no-string-throw": true, 42 | "no-switch-case-fall-through": true, 43 | "no-trailing-whitespace": true, 44 | "no-unnecessary-initializer": true, 45 | "no-unused-expression": true, 46 | "no-use-before-declare": true, 47 | "no-var-keyword": true, 48 | "object-literal-sort-keys": false, 49 | "one-line": [true, "check-open-brace", "check-catch", "check-else", "check-whitespace"], 50 | "prefer-const": true, 51 | "quotemark": [true, "single"], 52 | "radix": true, 53 | "semicolon": [true, "always"], 54 | "triple-equals": [true, "allow-null-check"], 55 | "typedef-whitespace": [ 56 | true, 57 | { 58 | "call-signature": "nospace", 59 | "index-signature": "nospace", 60 | "parameter": "nospace", 61 | "property-declaration": "nospace", 62 | "variable-declaration": "nospace" 63 | } 64 | ], 65 | "typeof-compare": true, 66 | "unified-signatures": true, 67 | "variable-name": false, 68 | "whitespace": [true, "check-branch", "check-decl", "check-operator", "check-separator", "check-type"], 69 | "directive-selector": [true, "attribute", "app", "camelCase"], 70 | "component-selector": [true, "element", "app", "kebab-case"], 71 | "no-output-on-prefix": true, 72 | "use-input-property-decorator": true, 73 | "use-output-property-decorator": true, 74 | "use-host-property-decorator": true, 75 | "no-input-rename": true, 76 | "no-output-rename": true, 77 | "use-life-cycle-interface": true, 78 | "use-pipe-transform-interface": true, 79 | "component-class-suffix": true, 80 | "directive-class-suffix": true 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/README.md: -------------------------------------------------------------------------------- 1 | # bower + script tags 2 | 3 | Example showing sticky states installed via hybrid npm and bower packages. 4 | Scripts are added using script tags in index.html. 5 | 6 | ## Running 7 | 8 | ``` 9 | npm install 10 | npm start 11 | ``` 12 | 13 | ## Info 14 | 15 | This example uses `angular` and `angular-ui-router` from bower. 16 | Because sticky states and visualizer are not published to bower, they are added to the `package.json` instead. 17 | 18 | Sticky states requires a reference to ui-router core. 19 | We're using the monolithic `angular-ui-router.js` bundle (which also bundles ui-router core). 20 | To expose ui-router core, we add a shim via a script tag: 21 | 22 | ``` 23 | 24 | 25 | 29 | 30 | 31 | 32 | ``` 33 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/app/about.component.js: -------------------------------------------------------------------------------- 1 | angular.module('app').component('about', { 2 | template: ` 3 |

This is a trivial Deep State Redirect example app

4 |
    5 |
  1. Active the continentlist state
  2. 6 |
  3. Select a continent
  4. 7 |
  5. Select a country
  6. 8 |
  7. Reactivate this state (about)
  8. 9 |
  9. 10 | Active the continents state again.
    11 | You are redirected to the previously active substate of continentlist (including parameters).
    12 | You should see the country you chose in the previous step. 13 |
  10. 14 |
15 | `, 16 | }); 17 | 18 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/app/continentList.component.js: -------------------------------------------------------------------------------- 1 | angular.module('app').component('continentList', { 2 | template: ` 3 |

Continents

4 | 5 | 6 | {{ continent }} 7 | 8 | 9 | 10 | `, 11 | bindings: { 12 | continents: '<', 13 | }, 14 | }); 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/app/countryDetail.component.js: -------------------------------------------------------------------------------- 1 | angular.module('app').component('countryDetail', { 2 | template: ` 3 |

{{ $ctrl.country }}

4 |
5 | 6 |
7 | `, 8 | controller: function () { 9 | this.imageSrc = function() { 10 | if (!this.country) { return ''; } 11 | const prefix = 'http://www.randomlists.com/img/national-flags/'; 12 | const imageName = this.country.toLowerCase().replace(/ /g, '_'); 13 | return `${prefix}${imageName}.gif`; 14 | }; 15 | }, 16 | bindings: { 17 | country: '<', 18 | }, 19 | }); 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/app/countryList.component.js: -------------------------------------------------------------------------------- 1 | angular.module('app').component('countryList', { 2 | template: ` 3 | 4 | 5 | 13 | `, 14 | bindings: { 15 | countries: '<', 16 | }, 17 | }); 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/app/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Afghanistan", 4 | "continent": "Asia" 5 | }, 6 | { 7 | "name": "Albania", 8 | "continent": "Europe" 9 | }, 10 | { 11 | "name": "Algeria", 12 | "continent": "Africa" 13 | }, 14 | { 15 | "name": "Andorra", 16 | "continent": "Europe" 17 | }, 18 | { 19 | "name": "Angola", 20 | "continent": "Africa" 21 | }, 22 | { 23 | "name": "Antigua and Barbuda", 24 | "continent": "America" 25 | }, 26 | { 27 | "name": "Argentina", 28 | "continent": "America" 29 | }, 30 | { 31 | "name": "Armenia", 32 | "continent": "Asia" 33 | }, 34 | { 35 | "name": "Australia", 36 | "continent": "Oceania" 37 | }, 38 | { 39 | "name": "Austria", 40 | "continent": "Europe" 41 | }, 42 | { 43 | "name": "Azerbaijan", 44 | "continent": "Asia" 45 | }, 46 | { 47 | "name": "Bahamas", 48 | "continent": "America" 49 | }, 50 | { 51 | "name": "Bahrain", 52 | "continent": "Asia" 53 | }, 54 | { 55 | "name": "Bangladesh", 56 | "continent": "Asia" 57 | }, 58 | { 59 | "name": "Barbados", 60 | "continent": "America" 61 | }, 62 | { 63 | "name": "Belarus", 64 | "continent": "Europe" 65 | }, 66 | { 67 | "name": "Belgium", 68 | "continent": "Europe" 69 | }, 70 | { 71 | "name": "Belize", 72 | "continent": "America" 73 | }, 74 | { 75 | "name": "Benin", 76 | "continent": "Africa" 77 | }, 78 | { 79 | "name": "Bhutan", 80 | "continent": "Asia" 81 | }, 82 | { 83 | "name": "Bolivia", 84 | "continent": "America" 85 | }, 86 | { 87 | "name": "Bosnia and Herzegovina", 88 | "continent": "Europe" 89 | }, 90 | { 91 | "name": "Botswana", 92 | "continent": "Africa" 93 | }, 94 | { 95 | "name": "Brazil", 96 | "continent": "America" 97 | }, 98 | { 99 | "name": "Brunei", 100 | "continent": "Asia" 101 | }, 102 | { 103 | "name": "Bulgaria", 104 | "continent": "Europe" 105 | }, 106 | { 107 | "name": "Burkina Faso", 108 | "continent": "Africa" 109 | }, 110 | { 111 | "name": "Myanmar", 112 | "continent": "Asia" 113 | }, 114 | { 115 | "name": "Burundi", 116 | "continent": "Africa" 117 | }, 118 | { 119 | "name": "Cambodia", 120 | "continent": "Asia" 121 | }, 122 | { 123 | "name": "Cameroon", 124 | "continent": "Africa" 125 | }, 126 | { 127 | "name": "Canada", 128 | "continent": "America" 129 | }, 130 | { 131 | "name": "Cape Verde", 132 | "continent": "Africa" 133 | }, 134 | { 135 | "name": "Central African Republic", 136 | "continent": "Africa" 137 | }, 138 | { 139 | "name": "Chad", 140 | "continent": "Africa" 141 | }, 142 | { 143 | "name": "Chile", 144 | "continent": "America" 145 | }, 146 | { 147 | "name": "China", 148 | "continent": "Asia" 149 | }, 150 | { 151 | "name": "Colombia", 152 | "continent": "America" 153 | }, 154 | { 155 | "name": "Comoros", 156 | "continent": "Africa" 157 | }, 158 | { 159 | "name": "Congo", 160 | "continent": "Africa" 161 | }, 162 | { 163 | "name": "Costa Rica", 164 | "continent": "America" 165 | }, 166 | { 167 | "name": "Croatia", 168 | "continent": "Europe" 169 | }, 170 | { 171 | "name": "Cuba", 172 | "continent": "America" 173 | }, 174 | { 175 | "name": "Cyprus", 176 | "continent": "Europe" 177 | }, 178 | { 179 | "name": "Czech Republic", 180 | "continent": "Europe" 181 | }, 182 | { 183 | "name": "Denmark", 184 | "continent": "Europe" 185 | }, 186 | { 187 | "name": "Djibouti", 188 | "continent": "Africa" 189 | }, 190 | { 191 | "name": "Dominica", 192 | "continent": "America" 193 | }, 194 | { 195 | "name": "Dominican Republic", 196 | "continent": "America" 197 | }, 198 | { 199 | "name": "East Timor", 200 | "continent": "Asia" 201 | }, 202 | { 203 | "name": "Ecuador", 204 | "continent": "America" 205 | }, 206 | { 207 | "name": "Egypt", 208 | "continent": "Africa" 209 | }, 210 | { 211 | "name": "El Salvador", 212 | "continent": "America" 213 | }, 214 | { 215 | "name": "England", 216 | "continent": "Europe" 217 | }, 218 | { 219 | "name": "Equatorial Guinea", 220 | "continent": "Africa" 221 | }, 222 | { 223 | "name": "Eritrea", 224 | "continent": "Africa" 225 | }, 226 | { 227 | "name": "Estonia", 228 | "continent": "Europe" 229 | }, 230 | { 231 | "name": "Ethiopia", 232 | "continent": "Africa" 233 | }, 234 | { 235 | "name": "Fiji", 236 | "continent": "Oceania" 237 | }, 238 | { 239 | "name": "Finland", 240 | "continent": "Europe" 241 | }, 242 | { 243 | "name": "France", 244 | "continent": "Europe" 245 | }, 246 | { 247 | "name": "Gabon", 248 | "continent": "Africa" 249 | }, 250 | { 251 | "name": "Gambia", 252 | "continent": "Africa" 253 | }, 254 | { 255 | "name": "Georgia", 256 | "continent": "Asia" 257 | }, 258 | { 259 | "name": "Germany", 260 | "continent": "Europe" 261 | }, 262 | { 263 | "name": "Ghana", 264 | "continent": "Africa" 265 | }, 266 | { 267 | "name": "Greece", 268 | "continent": "Europe" 269 | }, 270 | { 271 | "name": "Grenada", 272 | "continent": "America" 273 | }, 274 | { 275 | "name": "Guatemala", 276 | "continent": "America" 277 | }, 278 | { 279 | "name": "Guinea", 280 | "continent": "Africa" 281 | }, 282 | { 283 | "name": "Guinea-Bissau", 284 | "continent": "Africa" 285 | }, 286 | { 287 | "name": "Guyana", 288 | "continent": "America" 289 | }, 290 | { 291 | "name": "Haiti", 292 | "continent": "America" 293 | }, 294 | { 295 | "name": "Honduras", 296 | "continent": "America" 297 | }, 298 | { 299 | "name": "Hong Kong", 300 | "continent": "Asia" 301 | }, 302 | { 303 | "name": "Hungary", 304 | "continent": "Europe" 305 | }, 306 | { 307 | "name": "Iceland", 308 | "continent": "Europe" 309 | }, 310 | { 311 | "name": "India", 312 | "continent": "Asia" 313 | }, 314 | { 315 | "name": "Indonesia", 316 | "continent": "Asia" 317 | }, 318 | { 319 | "name": "Iran", 320 | "continent": "Asia" 321 | }, 322 | { 323 | "name": "Iraq", 324 | "continent": "Asia" 325 | }, 326 | { 327 | "name": "Ireland", 328 | "continent": "Europe" 329 | }, 330 | { 331 | "name": "Isle of Man", 332 | "continent": "Europe" 333 | }, 334 | { 335 | "name": "Israel", 336 | "continent": "Asia" 337 | }, 338 | { 339 | "name": "Italy", 340 | "continent": "Europe" 341 | }, 342 | { 343 | "name": "Jamaica", 344 | "continent": "America" 345 | }, 346 | { 347 | "name": "Japan", 348 | "continent": "Asia" 349 | }, 350 | { 351 | "name": "Jordan", 352 | "continent": "Asia" 353 | }, 354 | { 355 | "name": "Kazakhstan", 356 | "continent": "Asia" 357 | }, 358 | { 359 | "name": "Kenya", 360 | "continent": "Africa" 361 | }, 362 | { 363 | "name": "Kiribati", 364 | "continent": "Oceania" 365 | }, 366 | { 367 | "name": "North Korea", 368 | "continent": "Asia" 369 | }, 370 | { 371 | "name": "South Korea", 372 | "continent": "Asia" 373 | }, 374 | { 375 | "name": "Kosovo", 376 | "continent": "Europe" 377 | }, 378 | { 379 | "name": "Kuwait", 380 | "continent": "Asia" 381 | }, 382 | { 383 | "name": "Kyrgyzstan", 384 | "continent": "Asia" 385 | }, 386 | { 387 | "name": "Laos", 388 | "continent": "Asia" 389 | }, 390 | { 391 | "name": "Latvia", 392 | "continent": "Europe" 393 | }, 394 | { 395 | "name": "Lebanon", 396 | "continent": "Asia" 397 | }, 398 | { 399 | "name": "Lesotho", 400 | "continent": "Africa" 401 | }, 402 | { 403 | "name": "Liberia", 404 | "continent": "Africa" 405 | }, 406 | { 407 | "name": "Libya", 408 | "continent": "Africa" 409 | }, 410 | { 411 | "name": "Liechtenstein", 412 | "continent": "Europe" 413 | }, 414 | { 415 | "name": "Lithuania", 416 | "continent": "Europe" 417 | }, 418 | { 419 | "name": "Luxembourg", 420 | "continent": "Europe" 421 | }, 422 | { 423 | "name": "Macau", 424 | "continent": "Asia" 425 | }, 426 | { 427 | "name": "Macedonia", 428 | "continent": "Europe" 429 | }, 430 | { 431 | "name": "Madagascar", 432 | "continent": "Africa" 433 | }, 434 | { 435 | "name": "Malawi", 436 | "continent": "Africa" 437 | }, 438 | { 439 | "name": "Malaysia", 440 | "continent": "Asia" 441 | }, 442 | { 443 | "name": "Maldives", 444 | "continent": "Asia" 445 | }, 446 | { 447 | "name": "Mali", 448 | "continent": "Africa" 449 | }, 450 | { 451 | "name": "Malta", 452 | "continent": "Europe" 453 | }, 454 | { 455 | "name": "Marshall Islands", 456 | "continent": "Oceania" 457 | }, 458 | { 459 | "name": "Mauritania", 460 | "continent": "Africa" 461 | }, 462 | { 463 | "name": "Mauritius", 464 | "continent": "Africa" 465 | }, 466 | { 467 | "name": "Mexico", 468 | "continent": "America" 469 | }, 470 | { 471 | "name": "Micronesia", 472 | "continent": "Oceania" 473 | }, 474 | { 475 | "name": "Moldova", 476 | "continent": "Europe" 477 | }, 478 | { 479 | "name": "Monaco", 480 | "continent": "Europe" 481 | }, 482 | { 483 | "name": "Mongolia", 484 | "continent": "Asia" 485 | }, 486 | { 487 | "name": "Montenegro", 488 | "continent": "Europe" 489 | }, 490 | { 491 | "name": "Morocco", 492 | "continent": "Africa" 493 | }, 494 | { 495 | "name": "Mozambique", 496 | "continent": "Africa" 497 | }, 498 | { 499 | "name": "Namibia", 500 | "continent": "Africa" 501 | }, 502 | { 503 | "name": "Nauru", 504 | "continent": "Oceania" 505 | }, 506 | { 507 | "name": "Nepal", 508 | "continent": "Asia" 509 | }, 510 | { 511 | "name": "Netherlands", 512 | "continent": "Europe" 513 | }, 514 | { 515 | "name": "New Zealand", 516 | "continent": "Oceania" 517 | }, 518 | { 519 | "name": "Nicaragua", 520 | "continent": "America" 521 | }, 522 | { 523 | "name": "Niger", 524 | "continent": "Africa" 525 | }, 526 | { 527 | "name": "Nigeria", 528 | "continent": "Africa" 529 | }, 530 | { 531 | "name": "Norway", 532 | "continent": "Europe" 533 | }, 534 | { 535 | "name": "Oman", 536 | "continent": "Asia" 537 | }, 538 | { 539 | "name": "Pakistan", 540 | "continent": "Asia" 541 | }, 542 | { 543 | "name": "Palau", 544 | "continent": "Oceania" 545 | }, 546 | { 547 | "name": "Panama", 548 | "continent": "America" 549 | }, 550 | { 551 | "name": "Papua New Guinea", 552 | "continent": "Oceania" 553 | }, 554 | { 555 | "name": "Paraguay", 556 | "continent": "America" 557 | }, 558 | { 559 | "name": "Peru", 560 | "continent": "America" 561 | }, 562 | { 563 | "name": "Philippines", 564 | "continent": "Asia" 565 | }, 566 | { 567 | "name": "Poland", 568 | "continent": "Europe" 569 | }, 570 | { 571 | "name": "Portugal", 572 | "continent": "Europe" 573 | }, 574 | { 575 | "name": "Puerto Rico", 576 | "continent": "America" 577 | }, 578 | { 579 | "name": "Qatar", 580 | "continent": "Asia" 581 | }, 582 | { 583 | "name": "Romania", 584 | "continent": "Europe" 585 | }, 586 | { 587 | "name": "Russia", 588 | "continent": "Europe" 589 | }, 590 | { 591 | "name": "Rwanda", 592 | "continent": "Africa" 593 | }, 594 | { 595 | "name": "Saint Kitts and Nevis", 596 | "continent": "America" 597 | }, 598 | { 599 | "name": "Saint Lucia", 600 | "continent": "America" 601 | }, 602 | { 603 | "name": "Saint Vincent and the Grenadines", 604 | "continent": "America" 605 | }, 606 | { 607 | "name": "Samoa", 608 | "continent": "Oceania" 609 | }, 610 | { 611 | "name": "San Marino", 612 | "continent": "Europe" 613 | }, 614 | { 615 | "name": "Saudi Arabia", 616 | "continent": "Asia" 617 | }, 618 | { 619 | "name": "Scotland", 620 | "continent": "Europe" 621 | }, 622 | { 623 | "name": "Senegal", 624 | "continent": "Africa" 625 | }, 626 | { 627 | "name": "Serbia", 628 | "continent": "Europe" 629 | }, 630 | { 631 | "name": "Seychelles", 632 | "continent": "Africa" 633 | }, 634 | { 635 | "name": "Sierra Leone", 636 | "continent": "Africa" 637 | }, 638 | { 639 | "name": "Singapore", 640 | "continent": "Asia" 641 | }, 642 | { 643 | "name": "Slovakia", 644 | "continent": "Europe" 645 | }, 646 | { 647 | "name": "Slovenia", 648 | "continent": "Europe" 649 | }, 650 | { 651 | "name": "Solomon Islands", 652 | "continent": "Oceania" 653 | }, 654 | { 655 | "name": "Somalia", 656 | "continent": "Africa" 657 | }, 658 | { 659 | "name": "South Africa", 660 | "continent": "Africa" 661 | }, 662 | { 663 | "name": "Spain", 664 | "continent": "Europe" 665 | }, 666 | { 667 | "name": "Sri Lanka", 668 | "continent": "Asia" 669 | }, 670 | { 671 | "name": "Sudan", 672 | "continent": "Africa" 673 | }, 674 | { 675 | "name": "Suriname", 676 | "continent": "America" 677 | }, 678 | { 679 | "name": "Swaziland", 680 | "continent": "Africa" 681 | }, 682 | { 683 | "name": "Sweden", 684 | "continent": "Europe" 685 | }, 686 | { 687 | "name": "Switzerland", 688 | "continent": "Europe" 689 | }, 690 | { 691 | "name": "Syria", 692 | "continent": "Asia" 693 | }, 694 | { 695 | "name": "Taiwan", 696 | "continent": "Asia" 697 | }, 698 | { 699 | "name": "Tajikistan", 700 | "continent": "Asia" 701 | }, 702 | { 703 | "name": "Tanzania", 704 | "continent": "Africa" 705 | }, 706 | { 707 | "name": "Thailand", 708 | "continent": "Asia" 709 | }, 710 | { 711 | "name": "Togo", 712 | "continent": "Africa" 713 | }, 714 | { 715 | "name": "Tonga", 716 | "continent": "Oceania" 717 | }, 718 | { 719 | "name": "Trinidad and Tobago", 720 | "continent": "America" 721 | }, 722 | { 723 | "name": "Tunisia", 724 | "continent": "Africa" 725 | }, 726 | { 727 | "name": "Turkey", 728 | "continent": "Asia" 729 | }, 730 | { 731 | "name": "Turkmenistan", 732 | "continent": "Asia" 733 | }, 734 | { 735 | "name": "Tuvalu", 736 | "continent": "Oceania" 737 | }, 738 | { 739 | "name": "Uganda", 740 | "continent": "Africa" 741 | }, 742 | { 743 | "name": "Ukraine", 744 | "continent": "Europe" 745 | }, 746 | { 747 | "name": "United Arab Emirates", 748 | "continent": "Asia" 749 | }, 750 | { 751 | "name": "United Kingdom", 752 | "continent": "Europe" 753 | }, 754 | { 755 | "name": "United States of America", 756 | "continent": "America" 757 | }, 758 | { 759 | "name": "Uruguay", 760 | "continent": "America" 761 | }, 762 | { 763 | "name": "USSR", 764 | "continent": "Europe" 765 | }, 766 | { 767 | "name": "Uzbekistan", 768 | "continent": "Asia" 769 | }, 770 | { 771 | "name": "Vanuatu", 772 | "continent": "Oceania" 773 | }, 774 | { 775 | "name": "Vatican City", 776 | "continent": "Europe" 777 | }, 778 | { 779 | "name": "Venezuela", 780 | "continent": "America" 781 | }, 782 | { 783 | "name": "Vietnam", 784 | "continent": "Asia" 785 | }, 786 | { 787 | "name": "Wales", 788 | "continent": "Europe" 789 | }, 790 | { 791 | "name": "Yemen", 792 | "continent": "Asia" 793 | }, 794 | { 795 | "name": "Zambia", 796 | "continent": "Africa" 797 | }, 798 | { 799 | "name": "Zimbabwe", 800 | "continent": "Africa" 801 | } 802 | ] 803 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/app/index.js: -------------------------------------------------------------------------------- 1 | import './router.config'; 2 | 3 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/app/router.config.js: -------------------------------------------------------------------------------- 1 | console.log(window['@uirouter/visualizer']) 2 | var Visualizer = window['@uirouter/visualizer'].Visualizer; 3 | var DSRPlugin = window['@uirouter/dsr'].DSRPlugin; 4 | 5 | var states = [ 6 | { 7 | name: 'continentlist', 8 | url: '/continents', 9 | dsr: true, 10 | component: 'continentList', 11 | resolve: { 12 | 'continents': () => getContinents(), 13 | }, 14 | }, 15 | 16 | { 17 | name: 'continentlist.countrylist', 18 | url: '/:continent', 19 | component: 'countryList', 20 | resolve: { 21 | 'countries': ($transition$) => getCountries($transition$.params().continent), 22 | }, 23 | }, 24 | 25 | { 26 | name: 'continentlist.countrylist.countrydetail', 27 | url: '/:country', 28 | component: 'countryDetail', 29 | resolve: { 30 | 'country': ($transition$) => $transition$.params().country, 31 | }, 32 | }, 33 | 34 | { 35 | name: 'about', 36 | url: '/about', 37 | component: 'about', 38 | }, 39 | ]; 40 | 41 | angular.module('app', ['ui.router']).config(function ($uiRouterProvider) { 42 | $uiRouterProvider.plugin(DSRPlugin); 43 | $uiRouterProvider.plugin(Visualizer); 44 | 45 | // Add states 46 | states.forEach(state => $uiRouterProvider.stateRegistry.register(state)); 47 | 48 | // Set initial state 49 | $uiRouterProvider.urlService.rules.initial({ state: 'about' }); 50 | }); 51 | 52 | 53 | function getContinents() { 54 | return fetch('app/data.json').then(res => res.json()) 55 | .then(countries => countries.map(country => country.continent)) 56 | .then(continents => continents.reduce((acc, continent) => acc.includes(continent) ? acc : acc.concat(continent), [])) 57 | } 58 | 59 | function getCountries(continent) { 60 | return fetch('app/data.json').then(res => res.json()) 61 | .then(countries => countries.filter(country => country.continent === continent)) 62 | .then(countries => countries.map(country => country.name)); 63 | } 64 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-bower", 3 | "description": "AngularJS/bower sticky states example", 4 | "main": "index.js", 5 | "authors": [ 6 | "Chris Thielen " 7 | ], 8 | "license": "MIT", 9 | "homepage": "https://github.com/ui-router/sticky-states", 10 | "private": true, 11 | "resolvers": [ 12 | "bower-npm-resolver" 13 | ], 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "bower_components", 18 | "test", 19 | "tests" 20 | ], 21 | "dependencies": { 22 | "angular-ui-router": "^1.0.13", 23 | "angular": "^1.6.8" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:4000", 3 | "video": false 4 | } 5 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/cypress/integration/example_spec.js: -------------------------------------------------------------------------------- 1 | describe('example app', () => { 2 | it('loads', () => { 3 | cy.visit(''); 4 | }); 5 | 6 | it('renders links', () => { 7 | cy.visit('/'); 8 | cy.get('a').contains('about'); 9 | cy.get('a').contains('continentlist'); 10 | }); 11 | 12 | it('renders about by default', () => { 13 | cy.visit('/'); 14 | cy.contains('This is a trivial Deep State Redirect example app'); 15 | }); 16 | 17 | it('can navigate to continentlist', () => { 18 | cy.visit(''); 19 | cy 20 | .get('a') 21 | .contains('continentlist') 22 | .click(); 23 | 24 | cy.contains('Africa'); 25 | cy.contains('America'); 26 | cy.contains('Oceania'); 27 | }); 28 | 29 | it('can navigate to belize', () => { 30 | cy.visit(''); 31 | cy 32 | .get('a') 33 | .contains('continentlist') 34 | .click(); 35 | cy 36 | .get('a') 37 | .contains('America') 38 | .click(); 39 | cy 40 | .get('a') 41 | .contains('Belize') 42 | .click(); 43 | cy.get('h3').contains('Belize'); 44 | }); 45 | 46 | it('can navigate to belize and back', () => { 47 | cy.visit(''); 48 | cy 49 | .get('a') 50 | .contains('continentlist') 51 | .click(); 52 | cy 53 | .get('a') 54 | .contains('America') 55 | .click(); 56 | cy.url().should('include', '/America'); 57 | 58 | cy 59 | .get('a') 60 | .contains('Belize') 61 | .click(); 62 | cy.get('h3').contains('Belize'); 63 | cy.url().should('include', '/America/Belize'); 64 | 65 | cy 66 | .get('a') 67 | .contains('about') 68 | .click(); 69 | cy.contains('This is a trivial Deep State Redirect example app'); 70 | }); 71 | 72 | it('dsr sends you back to belize', () => { 73 | cy.visit(''); 74 | cy 75 | .get('a') 76 | .contains('continentlist') 77 | .click(); 78 | cy 79 | .get('a') 80 | .contains('America') 81 | .click(); 82 | cy.url().should('include', '/America'); 83 | 84 | cy 85 | .get('a') 86 | .contains('Belize') 87 | .click(); 88 | cy.url().should('include', '/America/Belize'); 89 | cy.get('h3').contains('Belize'); 90 | 91 | cy 92 | .get('a') 93 | .contains('about') 94 | .click(); 95 | cy.url().should('include', '/about'); 96 | cy.contains('This is a trivial Deep State Redirect example app'); 97 | 98 | cy 99 | .get('a') 100 | .contains('continentlist') 101 | .click(); 102 | cy.url().should('include', '/America/Belize'); 103 | cy.get('h3').contains('Belize'); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | about 21 | continentlist 22 | 23 | 24 |
25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/index.js: -------------------------------------------------------------------------------- 1 | var StickyStatesPlugin = window['@uirouter/sticky-states'].StickyStatesPlugin; 2 | var Visualizer = (window['@uirouter/visualizer'] || window['ui-router-visualizer']).Visualizer; 3 | 4 | // Create the module where our functionality can attach to 5 | var APP_MODULE = angular.module('app', ['ui.router']); 6 | 7 | APP_MODULE.config(function ($uiRouterProvider) { 8 | $uiRouterProvider.plugin(StickyStatesPlugin); 9 | $uiRouterProvider.plugin(Visualizer); 10 | 11 | // Add states 12 | var stateRegistry = $uiRouterProvider.stateRegistry; 13 | 14 | stateRegistry.register({ 15 | name: 'home', 16 | url: '/home', 17 | sticky: true, 18 | views: { 19 | home: 'generic', 20 | }, 21 | }); 22 | 23 | stateRegistry.register({ 24 | name: 'about', 25 | url: '/about', 26 | sticky: true, 27 | views: { 28 | about: 'generic', 29 | }, 30 | }); 31 | 32 | // Set initial state 33 | var urlService = $uiRouterProvider.urlService; 34 | urlService.rules.initial({ state: 'home' }) 35 | }); 36 | 37 | // Generic component 38 | APP_MODULE.component('generic', { 39 | template: ` 40 |

{{ $ctrl.$state$.name }} state loaded

41 | 42 | `, 43 | controller: function() { 44 | this.text = "Text entered here is not lost"; 45 | }, 46 | bindings: { '$state$': '<' }, 47 | }); 48 | 49 | APP_MODULE.run(function ($state, $rootScope) { 50 | $rootScope.$state = $state; 51 | }); 52 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-bower-script-tags", 3 | "version": "1.0.0", 4 | "description": "AngularJS/bower sticky states example", 5 | "main": "index.js", 6 | "scripts": { 7 | "postinstall": "bower install", 8 | "test": "cypress-runner run --path .", 9 | "test:open": "cypress-runner open --path .", 10 | "start": "lite-server" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "bower": "^1.8.2", 16 | "lite-server": "^2.3.0" 17 | }, 18 | "dependencies": { 19 | "@uirouter/cypress-runner": "^1.0.2", 20 | "@uirouter/dsr": "^1.0.2", 21 | "@uirouter/visualizer": "^6" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/angularjs-bower-script-tags/styles.css: -------------------------------------------------------------------------------- 1 | .active { 2 | font-weight: bold; 3 | } 4 | .container { 5 | display: flex; 6 | flex-flow: row wrap; 7 | } 8 | .container > * { 9 | border: 1px solid; 10 | padding: 0.5em; 11 | margin: 0.5em; 12 | flex: 1 1 75px; 13 | } 14 | .container > a.active { 15 | background: lightgray; 16 | } 17 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/README.md: -------------------------------------------------------------------------------- 1 | # npm + script tags 2 | 3 | Example showing sticky states installed via npm packages. 4 | Scripts are added using script tags in index.html. 5 | 6 | ## Running 7 | 8 | ``` 9 | npm install 10 | npm start 11 | ``` 12 | 13 | ## Info 14 | 15 | This example has separate script tags for `ui-router-core.js` from the `@uirouter/core` package and `ui-router-angularjs.js` from `@uirouter/angularjs` package. 16 | 17 | ``` 18 | 19 | 20 | 21 | 22 | 23 | 24 | ``` 25 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/app/about.component.js: -------------------------------------------------------------------------------- 1 | angular.module('app').component('about', { 2 | template: ` 3 |

This is a trivial Deep State Redirect example app

4 |
    5 |
  1. Active the continentlist state
  2. 6 |
  3. Select a continent
  4. 7 |
  5. Select a country
  6. 8 |
  7. Reactivate this state (about)
  8. 9 |
  9. 10 | Active the continents state again.
    11 | You are redirected to the previously active substate of continentlist (including parameters).
    12 | You should see the country you chose in the previous step. 13 |
  10. 14 |
15 | `, 16 | }); 17 | 18 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/app/continentList.component.js: -------------------------------------------------------------------------------- 1 | angular.module('app').component('continentList', { 2 | template: ` 3 |

Continents

4 | 5 | 6 | {{ continent }} 7 | 8 | 9 | 10 | `, 11 | bindings: { 12 | continents: '<', 13 | }, 14 | }); 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/app/countryDetail.component.js: -------------------------------------------------------------------------------- 1 | angular.module('app').component('countryDetail', { 2 | template: ` 3 |

{{ $ctrl.country }}

4 |
5 | 6 |
7 | `, 8 | controller: function () { 9 | this.imageSrc = function() { 10 | if (!this.country) { return ''; } 11 | const prefix = 'http://www.randomlists.com/img/national-flags/'; 12 | const imageName = this.country.toLowerCase().replace(/ /g, '_'); 13 | return `${prefix}${imageName}.gif`; 14 | }; 15 | }, 16 | bindings: { 17 | country: '<', 18 | }, 19 | }); 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/app/countryList.component.js: -------------------------------------------------------------------------------- 1 | angular.module('app').component('countryList', { 2 | template: ` 3 | 4 | 5 | 13 | `, 14 | bindings: { 15 | countries: '<', 16 | }, 17 | }); 18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/app/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Afghanistan", 4 | "continent": "Asia" 5 | }, 6 | { 7 | "name": "Albania", 8 | "continent": "Europe" 9 | }, 10 | { 11 | "name": "Algeria", 12 | "continent": "Africa" 13 | }, 14 | { 15 | "name": "Andorra", 16 | "continent": "Europe" 17 | }, 18 | { 19 | "name": "Angola", 20 | "continent": "Africa" 21 | }, 22 | { 23 | "name": "Antigua and Barbuda", 24 | "continent": "America" 25 | }, 26 | { 27 | "name": "Argentina", 28 | "continent": "America" 29 | }, 30 | { 31 | "name": "Armenia", 32 | "continent": "Asia" 33 | }, 34 | { 35 | "name": "Australia", 36 | "continent": "Oceania" 37 | }, 38 | { 39 | "name": "Austria", 40 | "continent": "Europe" 41 | }, 42 | { 43 | "name": "Azerbaijan", 44 | "continent": "Asia" 45 | }, 46 | { 47 | "name": "Bahamas", 48 | "continent": "America" 49 | }, 50 | { 51 | "name": "Bahrain", 52 | "continent": "Asia" 53 | }, 54 | { 55 | "name": "Bangladesh", 56 | "continent": "Asia" 57 | }, 58 | { 59 | "name": "Barbados", 60 | "continent": "America" 61 | }, 62 | { 63 | "name": "Belarus", 64 | "continent": "Europe" 65 | }, 66 | { 67 | "name": "Belgium", 68 | "continent": "Europe" 69 | }, 70 | { 71 | "name": "Belize", 72 | "continent": "America" 73 | }, 74 | { 75 | "name": "Benin", 76 | "continent": "Africa" 77 | }, 78 | { 79 | "name": "Bhutan", 80 | "continent": "Asia" 81 | }, 82 | { 83 | "name": "Bolivia", 84 | "continent": "America" 85 | }, 86 | { 87 | "name": "Bosnia and Herzegovina", 88 | "continent": "Europe" 89 | }, 90 | { 91 | "name": "Botswana", 92 | "continent": "Africa" 93 | }, 94 | { 95 | "name": "Brazil", 96 | "continent": "America" 97 | }, 98 | { 99 | "name": "Brunei", 100 | "continent": "Asia" 101 | }, 102 | { 103 | "name": "Bulgaria", 104 | "continent": "Europe" 105 | }, 106 | { 107 | "name": "Burkina Faso", 108 | "continent": "Africa" 109 | }, 110 | { 111 | "name": "Myanmar", 112 | "continent": "Asia" 113 | }, 114 | { 115 | "name": "Burundi", 116 | "continent": "Africa" 117 | }, 118 | { 119 | "name": "Cambodia", 120 | "continent": "Asia" 121 | }, 122 | { 123 | "name": "Cameroon", 124 | "continent": "Africa" 125 | }, 126 | { 127 | "name": "Canada", 128 | "continent": "America" 129 | }, 130 | { 131 | "name": "Cape Verde", 132 | "continent": "Africa" 133 | }, 134 | { 135 | "name": "Central African Republic", 136 | "continent": "Africa" 137 | }, 138 | { 139 | "name": "Chad", 140 | "continent": "Africa" 141 | }, 142 | { 143 | "name": "Chile", 144 | "continent": "America" 145 | }, 146 | { 147 | "name": "China", 148 | "continent": "Asia" 149 | }, 150 | { 151 | "name": "Colombia", 152 | "continent": "America" 153 | }, 154 | { 155 | "name": "Comoros", 156 | "continent": "Africa" 157 | }, 158 | { 159 | "name": "Congo", 160 | "continent": "Africa" 161 | }, 162 | { 163 | "name": "Costa Rica", 164 | "continent": "America" 165 | }, 166 | { 167 | "name": "Croatia", 168 | "continent": "Europe" 169 | }, 170 | { 171 | "name": "Cuba", 172 | "continent": "America" 173 | }, 174 | { 175 | "name": "Cyprus", 176 | "continent": "Europe" 177 | }, 178 | { 179 | "name": "Czech Republic", 180 | "continent": "Europe" 181 | }, 182 | { 183 | "name": "Denmark", 184 | "continent": "Europe" 185 | }, 186 | { 187 | "name": "Djibouti", 188 | "continent": "Africa" 189 | }, 190 | { 191 | "name": "Dominica", 192 | "continent": "America" 193 | }, 194 | { 195 | "name": "Dominican Republic", 196 | "continent": "America" 197 | }, 198 | { 199 | "name": "East Timor", 200 | "continent": "Asia" 201 | }, 202 | { 203 | "name": "Ecuador", 204 | "continent": "America" 205 | }, 206 | { 207 | "name": "Egypt", 208 | "continent": "Africa" 209 | }, 210 | { 211 | "name": "El Salvador", 212 | "continent": "America" 213 | }, 214 | { 215 | "name": "England", 216 | "continent": "Europe" 217 | }, 218 | { 219 | "name": "Equatorial Guinea", 220 | "continent": "Africa" 221 | }, 222 | { 223 | "name": "Eritrea", 224 | "continent": "Africa" 225 | }, 226 | { 227 | "name": "Estonia", 228 | "continent": "Europe" 229 | }, 230 | { 231 | "name": "Ethiopia", 232 | "continent": "Africa" 233 | }, 234 | { 235 | "name": "Fiji", 236 | "continent": "Oceania" 237 | }, 238 | { 239 | "name": "Finland", 240 | "continent": "Europe" 241 | }, 242 | { 243 | "name": "France", 244 | "continent": "Europe" 245 | }, 246 | { 247 | "name": "Gabon", 248 | "continent": "Africa" 249 | }, 250 | { 251 | "name": "Gambia", 252 | "continent": "Africa" 253 | }, 254 | { 255 | "name": "Georgia", 256 | "continent": "Asia" 257 | }, 258 | { 259 | "name": "Germany", 260 | "continent": "Europe" 261 | }, 262 | { 263 | "name": "Ghana", 264 | "continent": "Africa" 265 | }, 266 | { 267 | "name": "Greece", 268 | "continent": "Europe" 269 | }, 270 | { 271 | "name": "Grenada", 272 | "continent": "America" 273 | }, 274 | { 275 | "name": "Guatemala", 276 | "continent": "America" 277 | }, 278 | { 279 | "name": "Guinea", 280 | "continent": "Africa" 281 | }, 282 | { 283 | "name": "Guinea-Bissau", 284 | "continent": "Africa" 285 | }, 286 | { 287 | "name": "Guyana", 288 | "continent": "America" 289 | }, 290 | { 291 | "name": "Haiti", 292 | "continent": "America" 293 | }, 294 | { 295 | "name": "Honduras", 296 | "continent": "America" 297 | }, 298 | { 299 | "name": "Hong Kong", 300 | "continent": "Asia" 301 | }, 302 | { 303 | "name": "Hungary", 304 | "continent": "Europe" 305 | }, 306 | { 307 | "name": "Iceland", 308 | "continent": "Europe" 309 | }, 310 | { 311 | "name": "India", 312 | "continent": "Asia" 313 | }, 314 | { 315 | "name": "Indonesia", 316 | "continent": "Asia" 317 | }, 318 | { 319 | "name": "Iran", 320 | "continent": "Asia" 321 | }, 322 | { 323 | "name": "Iraq", 324 | "continent": "Asia" 325 | }, 326 | { 327 | "name": "Ireland", 328 | "continent": "Europe" 329 | }, 330 | { 331 | "name": "Isle of Man", 332 | "continent": "Europe" 333 | }, 334 | { 335 | "name": "Israel", 336 | "continent": "Asia" 337 | }, 338 | { 339 | "name": "Italy", 340 | "continent": "Europe" 341 | }, 342 | { 343 | "name": "Jamaica", 344 | "continent": "America" 345 | }, 346 | { 347 | "name": "Japan", 348 | "continent": "Asia" 349 | }, 350 | { 351 | "name": "Jordan", 352 | "continent": "Asia" 353 | }, 354 | { 355 | "name": "Kazakhstan", 356 | "continent": "Asia" 357 | }, 358 | { 359 | "name": "Kenya", 360 | "continent": "Africa" 361 | }, 362 | { 363 | "name": "Kiribati", 364 | "continent": "Oceania" 365 | }, 366 | { 367 | "name": "North Korea", 368 | "continent": "Asia" 369 | }, 370 | { 371 | "name": "South Korea", 372 | "continent": "Asia" 373 | }, 374 | { 375 | "name": "Kosovo", 376 | "continent": "Europe" 377 | }, 378 | { 379 | "name": "Kuwait", 380 | "continent": "Asia" 381 | }, 382 | { 383 | "name": "Kyrgyzstan", 384 | "continent": "Asia" 385 | }, 386 | { 387 | "name": "Laos", 388 | "continent": "Asia" 389 | }, 390 | { 391 | "name": "Latvia", 392 | "continent": "Europe" 393 | }, 394 | { 395 | "name": "Lebanon", 396 | "continent": "Asia" 397 | }, 398 | { 399 | "name": "Lesotho", 400 | "continent": "Africa" 401 | }, 402 | { 403 | "name": "Liberia", 404 | "continent": "Africa" 405 | }, 406 | { 407 | "name": "Libya", 408 | "continent": "Africa" 409 | }, 410 | { 411 | "name": "Liechtenstein", 412 | "continent": "Europe" 413 | }, 414 | { 415 | "name": "Lithuania", 416 | "continent": "Europe" 417 | }, 418 | { 419 | "name": "Luxembourg", 420 | "continent": "Europe" 421 | }, 422 | { 423 | "name": "Macau", 424 | "continent": "Asia" 425 | }, 426 | { 427 | "name": "Macedonia", 428 | "continent": "Europe" 429 | }, 430 | { 431 | "name": "Madagascar", 432 | "continent": "Africa" 433 | }, 434 | { 435 | "name": "Malawi", 436 | "continent": "Africa" 437 | }, 438 | { 439 | "name": "Malaysia", 440 | "continent": "Asia" 441 | }, 442 | { 443 | "name": "Maldives", 444 | "continent": "Asia" 445 | }, 446 | { 447 | "name": "Mali", 448 | "continent": "Africa" 449 | }, 450 | { 451 | "name": "Malta", 452 | "continent": "Europe" 453 | }, 454 | { 455 | "name": "Marshall Islands", 456 | "continent": "Oceania" 457 | }, 458 | { 459 | "name": "Mauritania", 460 | "continent": "Africa" 461 | }, 462 | { 463 | "name": "Mauritius", 464 | "continent": "Africa" 465 | }, 466 | { 467 | "name": "Mexico", 468 | "continent": "America" 469 | }, 470 | { 471 | "name": "Micronesia", 472 | "continent": "Oceania" 473 | }, 474 | { 475 | "name": "Moldova", 476 | "continent": "Europe" 477 | }, 478 | { 479 | "name": "Monaco", 480 | "continent": "Europe" 481 | }, 482 | { 483 | "name": "Mongolia", 484 | "continent": "Asia" 485 | }, 486 | { 487 | "name": "Montenegro", 488 | "continent": "Europe" 489 | }, 490 | { 491 | "name": "Morocco", 492 | "continent": "Africa" 493 | }, 494 | { 495 | "name": "Mozambique", 496 | "continent": "Africa" 497 | }, 498 | { 499 | "name": "Namibia", 500 | "continent": "Africa" 501 | }, 502 | { 503 | "name": "Nauru", 504 | "continent": "Oceania" 505 | }, 506 | { 507 | "name": "Nepal", 508 | "continent": "Asia" 509 | }, 510 | { 511 | "name": "Netherlands", 512 | "continent": "Europe" 513 | }, 514 | { 515 | "name": "New Zealand", 516 | "continent": "Oceania" 517 | }, 518 | { 519 | "name": "Nicaragua", 520 | "continent": "America" 521 | }, 522 | { 523 | "name": "Niger", 524 | "continent": "Africa" 525 | }, 526 | { 527 | "name": "Nigeria", 528 | "continent": "Africa" 529 | }, 530 | { 531 | "name": "Norway", 532 | "continent": "Europe" 533 | }, 534 | { 535 | "name": "Oman", 536 | "continent": "Asia" 537 | }, 538 | { 539 | "name": "Pakistan", 540 | "continent": "Asia" 541 | }, 542 | { 543 | "name": "Palau", 544 | "continent": "Oceania" 545 | }, 546 | { 547 | "name": "Panama", 548 | "continent": "America" 549 | }, 550 | { 551 | "name": "Papua New Guinea", 552 | "continent": "Oceania" 553 | }, 554 | { 555 | "name": "Paraguay", 556 | "continent": "America" 557 | }, 558 | { 559 | "name": "Peru", 560 | "continent": "America" 561 | }, 562 | { 563 | "name": "Philippines", 564 | "continent": "Asia" 565 | }, 566 | { 567 | "name": "Poland", 568 | "continent": "Europe" 569 | }, 570 | { 571 | "name": "Portugal", 572 | "continent": "Europe" 573 | }, 574 | { 575 | "name": "Puerto Rico", 576 | "continent": "America" 577 | }, 578 | { 579 | "name": "Qatar", 580 | "continent": "Asia" 581 | }, 582 | { 583 | "name": "Romania", 584 | "continent": "Europe" 585 | }, 586 | { 587 | "name": "Russia", 588 | "continent": "Europe" 589 | }, 590 | { 591 | "name": "Rwanda", 592 | "continent": "Africa" 593 | }, 594 | { 595 | "name": "Saint Kitts and Nevis", 596 | "continent": "America" 597 | }, 598 | { 599 | "name": "Saint Lucia", 600 | "continent": "America" 601 | }, 602 | { 603 | "name": "Saint Vincent and the Grenadines", 604 | "continent": "America" 605 | }, 606 | { 607 | "name": "Samoa", 608 | "continent": "Oceania" 609 | }, 610 | { 611 | "name": "San Marino", 612 | "continent": "Europe" 613 | }, 614 | { 615 | "name": "Saudi Arabia", 616 | "continent": "Asia" 617 | }, 618 | { 619 | "name": "Scotland", 620 | "continent": "Europe" 621 | }, 622 | { 623 | "name": "Senegal", 624 | "continent": "Africa" 625 | }, 626 | { 627 | "name": "Serbia", 628 | "continent": "Europe" 629 | }, 630 | { 631 | "name": "Seychelles", 632 | "continent": "Africa" 633 | }, 634 | { 635 | "name": "Sierra Leone", 636 | "continent": "Africa" 637 | }, 638 | { 639 | "name": "Singapore", 640 | "continent": "Asia" 641 | }, 642 | { 643 | "name": "Slovakia", 644 | "continent": "Europe" 645 | }, 646 | { 647 | "name": "Slovenia", 648 | "continent": "Europe" 649 | }, 650 | { 651 | "name": "Solomon Islands", 652 | "continent": "Oceania" 653 | }, 654 | { 655 | "name": "Somalia", 656 | "continent": "Africa" 657 | }, 658 | { 659 | "name": "South Africa", 660 | "continent": "Africa" 661 | }, 662 | { 663 | "name": "Spain", 664 | "continent": "Europe" 665 | }, 666 | { 667 | "name": "Sri Lanka", 668 | "continent": "Asia" 669 | }, 670 | { 671 | "name": "Sudan", 672 | "continent": "Africa" 673 | }, 674 | { 675 | "name": "Suriname", 676 | "continent": "America" 677 | }, 678 | { 679 | "name": "Swaziland", 680 | "continent": "Africa" 681 | }, 682 | { 683 | "name": "Sweden", 684 | "continent": "Europe" 685 | }, 686 | { 687 | "name": "Switzerland", 688 | "continent": "Europe" 689 | }, 690 | { 691 | "name": "Syria", 692 | "continent": "Asia" 693 | }, 694 | { 695 | "name": "Taiwan", 696 | "continent": "Asia" 697 | }, 698 | { 699 | "name": "Tajikistan", 700 | "continent": "Asia" 701 | }, 702 | { 703 | "name": "Tanzania", 704 | "continent": "Africa" 705 | }, 706 | { 707 | "name": "Thailand", 708 | "continent": "Asia" 709 | }, 710 | { 711 | "name": "Togo", 712 | "continent": "Africa" 713 | }, 714 | { 715 | "name": "Tonga", 716 | "continent": "Oceania" 717 | }, 718 | { 719 | "name": "Trinidad and Tobago", 720 | "continent": "America" 721 | }, 722 | { 723 | "name": "Tunisia", 724 | "continent": "Africa" 725 | }, 726 | { 727 | "name": "Turkey", 728 | "continent": "Asia" 729 | }, 730 | { 731 | "name": "Turkmenistan", 732 | "continent": "Asia" 733 | }, 734 | { 735 | "name": "Tuvalu", 736 | "continent": "Oceania" 737 | }, 738 | { 739 | "name": "Uganda", 740 | "continent": "Africa" 741 | }, 742 | { 743 | "name": "Ukraine", 744 | "continent": "Europe" 745 | }, 746 | { 747 | "name": "United Arab Emirates", 748 | "continent": "Asia" 749 | }, 750 | { 751 | "name": "United Kingdom", 752 | "continent": "Europe" 753 | }, 754 | { 755 | "name": "United States of America", 756 | "continent": "America" 757 | }, 758 | { 759 | "name": "Uruguay", 760 | "continent": "America" 761 | }, 762 | { 763 | "name": "USSR", 764 | "continent": "Europe" 765 | }, 766 | { 767 | "name": "Uzbekistan", 768 | "continent": "Asia" 769 | }, 770 | { 771 | "name": "Vanuatu", 772 | "continent": "Oceania" 773 | }, 774 | { 775 | "name": "Vatican City", 776 | "continent": "Europe" 777 | }, 778 | { 779 | "name": "Venezuela", 780 | "continent": "America" 781 | }, 782 | { 783 | "name": "Vietnam", 784 | "continent": "Asia" 785 | }, 786 | { 787 | "name": "Wales", 788 | "continent": "Europe" 789 | }, 790 | { 791 | "name": "Yemen", 792 | "continent": "Asia" 793 | }, 794 | { 795 | "name": "Zambia", 796 | "continent": "Africa" 797 | }, 798 | { 799 | "name": "Zimbabwe", 800 | "continent": "Africa" 801 | } 802 | ] 803 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/app/index.js: -------------------------------------------------------------------------------- 1 | import './router.config'; 2 | 3 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/app/router.config.js: -------------------------------------------------------------------------------- 1 | console.log(window['@uirouter/visualizer']) 2 | var Visualizer = window['@uirouter/visualizer'].Visualizer; 3 | var DSRPlugin = window['@uirouter/dsr'].DSRPlugin; 4 | 5 | var states = [ 6 | { 7 | name: 'continentlist', 8 | url: '/continents', 9 | dsr: true, 10 | component: 'continentList', 11 | resolve: { 12 | 'continents': () => getContinents(), 13 | }, 14 | }, 15 | 16 | { 17 | name: 'continentlist.countrylist', 18 | url: '/:continent', 19 | component: 'countryList', 20 | resolve: { 21 | 'countries': ($transition$) => getCountries($transition$.params().continent), 22 | }, 23 | }, 24 | 25 | { 26 | name: 'continentlist.countrylist.countrydetail', 27 | url: '/:country', 28 | component: 'countryDetail', 29 | resolve: { 30 | 'country': ($transition$) => $transition$.params().country, 31 | }, 32 | }, 33 | 34 | { 35 | name: 'about', 36 | url: '/about', 37 | component: 'about', 38 | }, 39 | ]; 40 | 41 | angular.module('app', ['ui.router']).config(function ($uiRouterProvider) { 42 | $uiRouterProvider.plugin(DSRPlugin); 43 | $uiRouterProvider.plugin(Visualizer); 44 | 45 | // Add states 46 | states.forEach(state => $uiRouterProvider.stateRegistry.register(state)); 47 | 48 | // Set initial state 49 | $uiRouterProvider.urlService.rules.initial({ state: 'about' }); 50 | }); 51 | 52 | 53 | function getContinents() { 54 | return fetch('app/data.json').then(res => res.json()) 55 | .then(countries => countries.map(country => country.continent)) 56 | .then(continents => continents.reduce((acc, continent) => acc.includes(continent) ? acc : acc.concat(continent), [])) 57 | } 58 | 59 | function getCountries(continent) { 60 | return fetch('app/data.json').then(res => res.json()) 61 | .then(countries => countries.filter(country => country.continent === continent)) 62 | .then(countries => countries.map(country => country.name)); 63 | } 64 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:4000", 3 | "video": false 4 | } 5 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/cypress/integration/example_spec.js: -------------------------------------------------------------------------------- 1 | describe('example app', () => { 2 | it('loads', () => { 3 | cy.visit(''); 4 | }); 5 | 6 | it('renders links', () => { 7 | cy.visit('/'); 8 | cy.get('a').contains('about'); 9 | cy.get('a').contains('continentlist'); 10 | }); 11 | 12 | it('renders about by default', () => { 13 | cy.visit('/'); 14 | cy.contains('This is a trivial Deep State Redirect example app'); 15 | }); 16 | 17 | it('can navigate to continentlist', () => { 18 | cy.visit(''); 19 | cy 20 | .get('a') 21 | .contains('continentlist') 22 | .click(); 23 | 24 | cy.contains('Africa'); 25 | cy.contains('America'); 26 | cy.contains('Oceania'); 27 | }); 28 | 29 | it('can navigate to belize', () => { 30 | cy.visit(''); 31 | cy 32 | .get('a') 33 | .contains('continentlist') 34 | .click(); 35 | cy 36 | .get('a') 37 | .contains('America') 38 | .click(); 39 | cy 40 | .get('a') 41 | .contains('Belize') 42 | .click(); 43 | cy.get('h3').contains('Belize'); 44 | }); 45 | 46 | it('can navigate to belize and back', () => { 47 | cy.visit(''); 48 | cy 49 | .get('a') 50 | .contains('continentlist') 51 | .click(); 52 | cy 53 | .get('a') 54 | .contains('America') 55 | .click(); 56 | cy.url().should('include', '/America'); 57 | 58 | cy 59 | .get('a') 60 | .contains('Belize') 61 | .click(); 62 | cy.get('h3').contains('Belize'); 63 | cy.url().should('include', '/America/Belize'); 64 | 65 | cy 66 | .get('a') 67 | .contains('about') 68 | .click(); 69 | cy.contains('This is a trivial Deep State Redirect example app'); 70 | }); 71 | 72 | it('dsr sends you back to belize', () => { 73 | cy.visit(''); 74 | cy 75 | .get('a') 76 | .contains('continentlist') 77 | .click(); 78 | cy 79 | .get('a') 80 | .contains('America') 81 | .click(); 82 | cy.url().should('include', '/America'); 83 | 84 | cy 85 | .get('a') 86 | .contains('Belize') 87 | .click(); 88 | cy.url().should('include', '/America/Belize'); 89 | cy.get('h3').contains('Belize'); 90 | 91 | cy 92 | .get('a') 93 | .contains('about') 94 | .click(); 95 | cy.url().should('include', '/about'); 96 | cy.contains('This is a trivial Deep State Redirect example app'); 97 | 98 | cy 99 | .get('a') 100 | .contains('continentlist') 101 | .click(); 102 | cy.url().should('include', '/America/Belize'); 103 | cy.get('h3').contains('Belize'); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | about 18 | continentlist 19 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/index.js: -------------------------------------------------------------------------------- 1 | var StickyStatesPlugin = window['@uirouter/sticky-states'].StickyStatesPlugin; 2 | var Visualizer = (window['@uirouter/visualizer'] || window['ui-router-visualizer']).Visualizer; 3 | 4 | // Create the module where our functionality can attach to 5 | var APP_MODULE = angular.module('app', ['ui.router']); 6 | 7 | APP_MODULE.config(function ($uiRouterProvider) { 8 | $uiRouterProvider.plugin(StickyStatesPlugin); 9 | $uiRouterProvider.plugin(Visualizer); 10 | 11 | // Add states 12 | var stateRegistry = $uiRouterProvider.stateRegistry; 13 | 14 | stateRegistry.register({ 15 | name: 'home', 16 | url: '/home', 17 | sticky: true, 18 | views: { 19 | home: 'generic', 20 | }, 21 | }); 22 | 23 | stateRegistry.register({ 24 | name: 'about', 25 | url: '/about', 26 | sticky: true, 27 | views: { 28 | about: 'generic', 29 | }, 30 | }); 31 | 32 | // Set initial state 33 | var urlService = $uiRouterProvider.urlService; 34 | urlService.rules.initial({ state: 'home' }) 35 | }); 36 | 37 | // Generic component 38 | APP_MODULE.component('generic', { 39 | template: ` 40 |

{{ $ctrl.$state$.name }} state loaded

41 | 42 | `, 43 | controller: function() { 44 | this.text = "Text entered here is not lost"; 45 | }, 46 | bindings: { '$state$': '<' }, 47 | }); 48 | 49 | APP_MODULE.run(function ($state, $rootScope) { 50 | $rootScope.$state = $state; 51 | }); 52 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-npm-script-tags", 3 | "version": "1.0.0", 4 | "description": "AngularJS/bower sticky states example", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "cypress-runner run --path dist", 8 | "test:open": "cypress-runner open --path dist", 9 | "start": "lite-server" 10 | }, 11 | "author": "", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@uirouter/cypress-runner": "^1.0.2" 15 | }, 16 | "dependencies": { 17 | "@uirouter/angularjs": "^1.0.13", 18 | "@uirouter/dsr": "^1.0.2", 19 | "@uirouter/sticky-states": "^1.4.1", 20 | "@uirouter/visualizer": "^6", 21 | "angular": "^1.6.8" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/angularjs-npm-script-tags/styles.css: -------------------------------------------------------------------------------- 1 | .active { 2 | font-weight: bold; 3 | } 4 | .container { 5 | display: flex; 6 | flex-flow: row wrap; 7 | } 8 | .container > * { 9 | border: 1px solid; 10 | padding: 0.5em; 11 | margin: 0.5em; 12 | flex: 1 1 75px; 13 | } 14 | .container > a.active { 15 | background: lightgray; 16 | } 17 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/README.md: -------------------------------------------------------------------------------- 1 | # bower + script tags 2 | 3 | Example showing sticky states installed via npm packages. 4 | The app is bundled using webpack. 5 | 6 | ## Running 7 | 8 | ``` 9 | npm install 10 | npm start 11 | ``` 12 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/app/about.component.js: -------------------------------------------------------------------------------- 1 | import { APP_MODULE } from './app.module'; 2 | APP_MODULE.component('about', { 3 | template: ` 4 |

This is a trivial Deep State Redirect example app

5 |
    6 |
  1. Active the continentlist state
  2. 7 |
  3. Select a continent
  4. 8 |
  5. Select a country
  6. 9 |
  7. Reactivate this state (about)
  8. 10 |
  9. 11 | Active the continents state again.
    12 | You are redirected to the previously active substate of continentlist (including parameters).
    13 | You should see the country you chose in the previous step. 14 |
  10. 15 |
16 | `, 17 | }); 18 | 19 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/app/app.module.js: -------------------------------------------------------------------------------- 1 | import angular from 'angular'; 2 | import UIROUTER from '@uirouter/angularjs'; 3 | 4 | // Create the module where our functionality can attach to 5 | export const APP_MODULE = angular.module('app', [UIROUTER]); 6 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/app/continentList.component.js: -------------------------------------------------------------------------------- 1 | import { APP_MODULE } from './app.module'; 2 | APP_MODULE.component('continentList', { 3 | template: ` 4 |

Continents

5 | 6 | 7 | {{ continent }} 8 | 9 | 10 | 11 | `, 12 | bindings: { 13 | continents: '<', 14 | }, 15 | }); 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/app/countryDetail.component.js: -------------------------------------------------------------------------------- 1 | import { APP_MODULE } from './app.module'; 2 | APP_MODULE.component('countryDetail', { 3 | template: ` 4 |

{{ $ctrl.country }}

5 |
6 | 7 |
8 | `, 9 | controller: function () { 10 | this.imageSrc = function() { 11 | if (!this.country) { return ''; } 12 | const prefix = 'http://www.randomlists.com/img/national-flags/'; 13 | const imageName = this.country.toLowerCase().replace(/ /g, '_'); 14 | return `${prefix}${imageName}.gif`; 15 | }; 16 | }, 17 | bindings: { 18 | country: '<', 19 | }, 20 | }); 21 | 22 | 23 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/app/countryList.component.js: -------------------------------------------------------------------------------- 1 | import { APP_MODULE } from './app.module'; 2 | APP_MODULE.component('countryList', { 3 | template: ` 4 | 5 | 6 | 14 | `, 15 | bindings: { 16 | countries: '<', 17 | }, 18 | }); 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/app/data.api.js: -------------------------------------------------------------------------------- 1 | function getContinents() { 2 | return Promise.resolve(require('./data.json')) 3 | .then(countries => countries.map(country => country.continent)) 4 | .then(continents => continents.reduce((acc, continent) => acc.includes(continent) ? acc : acc.concat(continent), [])) 5 | } 6 | 7 | function getCountries(continent) { 8 | return Promise.resolve(require('./data.json')) 9 | .then(countries => countries.filter(country => country.continent === continent)) 10 | .then(countries => countries.map(country => country.name)); 11 | } 12 | 13 | export { getContinents, getCountries }; 14 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/app/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Afghanistan", 4 | "continent": "Asia" 5 | }, 6 | { 7 | "name": "Albania", 8 | "continent": "Europe" 9 | }, 10 | { 11 | "name": "Algeria", 12 | "continent": "Africa" 13 | }, 14 | { 15 | "name": "Andorra", 16 | "continent": "Europe" 17 | }, 18 | { 19 | "name": "Angola", 20 | "continent": "Africa" 21 | }, 22 | { 23 | "name": "Antigua and Barbuda", 24 | "continent": "America" 25 | }, 26 | { 27 | "name": "Argentina", 28 | "continent": "America" 29 | }, 30 | { 31 | "name": "Armenia", 32 | "continent": "Asia" 33 | }, 34 | { 35 | "name": "Australia", 36 | "continent": "Oceania" 37 | }, 38 | { 39 | "name": "Austria", 40 | "continent": "Europe" 41 | }, 42 | { 43 | "name": "Azerbaijan", 44 | "continent": "Asia" 45 | }, 46 | { 47 | "name": "Bahamas", 48 | "continent": "America" 49 | }, 50 | { 51 | "name": "Bahrain", 52 | "continent": "Asia" 53 | }, 54 | { 55 | "name": "Bangladesh", 56 | "continent": "Asia" 57 | }, 58 | { 59 | "name": "Barbados", 60 | "continent": "America" 61 | }, 62 | { 63 | "name": "Belarus", 64 | "continent": "Europe" 65 | }, 66 | { 67 | "name": "Belgium", 68 | "continent": "Europe" 69 | }, 70 | { 71 | "name": "Belize", 72 | "continent": "America" 73 | }, 74 | { 75 | "name": "Benin", 76 | "continent": "Africa" 77 | }, 78 | { 79 | "name": "Bhutan", 80 | "continent": "Asia" 81 | }, 82 | { 83 | "name": "Bolivia", 84 | "continent": "America" 85 | }, 86 | { 87 | "name": "Bosnia and Herzegovina", 88 | "continent": "Europe" 89 | }, 90 | { 91 | "name": "Botswana", 92 | "continent": "Africa" 93 | }, 94 | { 95 | "name": "Brazil", 96 | "continent": "America" 97 | }, 98 | { 99 | "name": "Brunei", 100 | "continent": "Asia" 101 | }, 102 | { 103 | "name": "Bulgaria", 104 | "continent": "Europe" 105 | }, 106 | { 107 | "name": "Burkina Faso", 108 | "continent": "Africa" 109 | }, 110 | { 111 | "name": "Myanmar", 112 | "continent": "Asia" 113 | }, 114 | { 115 | "name": "Burundi", 116 | "continent": "Africa" 117 | }, 118 | { 119 | "name": "Cambodia", 120 | "continent": "Asia" 121 | }, 122 | { 123 | "name": "Cameroon", 124 | "continent": "Africa" 125 | }, 126 | { 127 | "name": "Canada", 128 | "continent": "America" 129 | }, 130 | { 131 | "name": "Cape Verde", 132 | "continent": "Africa" 133 | }, 134 | { 135 | "name": "Central African Republic", 136 | "continent": "Africa" 137 | }, 138 | { 139 | "name": "Chad", 140 | "continent": "Africa" 141 | }, 142 | { 143 | "name": "Chile", 144 | "continent": "America" 145 | }, 146 | { 147 | "name": "China", 148 | "continent": "Asia" 149 | }, 150 | { 151 | "name": "Colombia", 152 | "continent": "America" 153 | }, 154 | { 155 | "name": "Comoros", 156 | "continent": "Africa" 157 | }, 158 | { 159 | "name": "Congo", 160 | "continent": "Africa" 161 | }, 162 | { 163 | "name": "Costa Rica", 164 | "continent": "America" 165 | }, 166 | { 167 | "name": "Croatia", 168 | "continent": "Europe" 169 | }, 170 | { 171 | "name": "Cuba", 172 | "continent": "America" 173 | }, 174 | { 175 | "name": "Cyprus", 176 | "continent": "Europe" 177 | }, 178 | { 179 | "name": "Czech Republic", 180 | "continent": "Europe" 181 | }, 182 | { 183 | "name": "Denmark", 184 | "continent": "Europe" 185 | }, 186 | { 187 | "name": "Djibouti", 188 | "continent": "Africa" 189 | }, 190 | { 191 | "name": "Dominica", 192 | "continent": "America" 193 | }, 194 | { 195 | "name": "Dominican Republic", 196 | "continent": "America" 197 | }, 198 | { 199 | "name": "East Timor", 200 | "continent": "Asia" 201 | }, 202 | { 203 | "name": "Ecuador", 204 | "continent": "America" 205 | }, 206 | { 207 | "name": "Egypt", 208 | "continent": "Africa" 209 | }, 210 | { 211 | "name": "El Salvador", 212 | "continent": "America" 213 | }, 214 | { 215 | "name": "England", 216 | "continent": "Europe" 217 | }, 218 | { 219 | "name": "Equatorial Guinea", 220 | "continent": "Africa" 221 | }, 222 | { 223 | "name": "Eritrea", 224 | "continent": "Africa" 225 | }, 226 | { 227 | "name": "Estonia", 228 | "continent": "Europe" 229 | }, 230 | { 231 | "name": "Ethiopia", 232 | "continent": "Africa" 233 | }, 234 | { 235 | "name": "Fiji", 236 | "continent": "Oceania" 237 | }, 238 | { 239 | "name": "Finland", 240 | "continent": "Europe" 241 | }, 242 | { 243 | "name": "France", 244 | "continent": "Europe" 245 | }, 246 | { 247 | "name": "Gabon", 248 | "continent": "Africa" 249 | }, 250 | { 251 | "name": "Gambia", 252 | "continent": "Africa" 253 | }, 254 | { 255 | "name": "Georgia", 256 | "continent": "Asia" 257 | }, 258 | { 259 | "name": "Germany", 260 | "continent": "Europe" 261 | }, 262 | { 263 | "name": "Ghana", 264 | "continent": "Africa" 265 | }, 266 | { 267 | "name": "Greece", 268 | "continent": "Europe" 269 | }, 270 | { 271 | "name": "Grenada", 272 | "continent": "America" 273 | }, 274 | { 275 | "name": "Guatemala", 276 | "continent": "America" 277 | }, 278 | { 279 | "name": "Guinea", 280 | "continent": "Africa" 281 | }, 282 | { 283 | "name": "Guinea-Bissau", 284 | "continent": "Africa" 285 | }, 286 | { 287 | "name": "Guyana", 288 | "continent": "America" 289 | }, 290 | { 291 | "name": "Haiti", 292 | "continent": "America" 293 | }, 294 | { 295 | "name": "Honduras", 296 | "continent": "America" 297 | }, 298 | { 299 | "name": "Hong Kong", 300 | "continent": "Asia" 301 | }, 302 | { 303 | "name": "Hungary", 304 | "continent": "Europe" 305 | }, 306 | { 307 | "name": "Iceland", 308 | "continent": "Europe" 309 | }, 310 | { 311 | "name": "India", 312 | "continent": "Asia" 313 | }, 314 | { 315 | "name": "Indonesia", 316 | "continent": "Asia" 317 | }, 318 | { 319 | "name": "Iran", 320 | "continent": "Asia" 321 | }, 322 | { 323 | "name": "Iraq", 324 | "continent": "Asia" 325 | }, 326 | { 327 | "name": "Ireland", 328 | "continent": "Europe" 329 | }, 330 | { 331 | "name": "Isle of Man", 332 | "continent": "Europe" 333 | }, 334 | { 335 | "name": "Israel", 336 | "continent": "Asia" 337 | }, 338 | { 339 | "name": "Italy", 340 | "continent": "Europe" 341 | }, 342 | { 343 | "name": "Jamaica", 344 | "continent": "America" 345 | }, 346 | { 347 | "name": "Japan", 348 | "continent": "Asia" 349 | }, 350 | { 351 | "name": "Jordan", 352 | "continent": "Asia" 353 | }, 354 | { 355 | "name": "Kazakhstan", 356 | "continent": "Asia" 357 | }, 358 | { 359 | "name": "Kenya", 360 | "continent": "Africa" 361 | }, 362 | { 363 | "name": "Kiribati", 364 | "continent": "Oceania" 365 | }, 366 | { 367 | "name": "North Korea", 368 | "continent": "Asia" 369 | }, 370 | { 371 | "name": "South Korea", 372 | "continent": "Asia" 373 | }, 374 | { 375 | "name": "Kosovo", 376 | "continent": "Europe" 377 | }, 378 | { 379 | "name": "Kuwait", 380 | "continent": "Asia" 381 | }, 382 | { 383 | "name": "Kyrgyzstan", 384 | "continent": "Asia" 385 | }, 386 | { 387 | "name": "Laos", 388 | "continent": "Asia" 389 | }, 390 | { 391 | "name": "Latvia", 392 | "continent": "Europe" 393 | }, 394 | { 395 | "name": "Lebanon", 396 | "continent": "Asia" 397 | }, 398 | { 399 | "name": "Lesotho", 400 | "continent": "Africa" 401 | }, 402 | { 403 | "name": "Liberia", 404 | "continent": "Africa" 405 | }, 406 | { 407 | "name": "Libya", 408 | "continent": "Africa" 409 | }, 410 | { 411 | "name": "Liechtenstein", 412 | "continent": "Europe" 413 | }, 414 | { 415 | "name": "Lithuania", 416 | "continent": "Europe" 417 | }, 418 | { 419 | "name": "Luxembourg", 420 | "continent": "Europe" 421 | }, 422 | { 423 | "name": "Macau", 424 | "continent": "Asia" 425 | }, 426 | { 427 | "name": "Macedonia", 428 | "continent": "Europe" 429 | }, 430 | { 431 | "name": "Madagascar", 432 | "continent": "Africa" 433 | }, 434 | { 435 | "name": "Malawi", 436 | "continent": "Africa" 437 | }, 438 | { 439 | "name": "Malaysia", 440 | "continent": "Asia" 441 | }, 442 | { 443 | "name": "Maldives", 444 | "continent": "Asia" 445 | }, 446 | { 447 | "name": "Mali", 448 | "continent": "Africa" 449 | }, 450 | { 451 | "name": "Malta", 452 | "continent": "Europe" 453 | }, 454 | { 455 | "name": "Marshall Islands", 456 | "continent": "Oceania" 457 | }, 458 | { 459 | "name": "Mauritania", 460 | "continent": "Africa" 461 | }, 462 | { 463 | "name": "Mauritius", 464 | "continent": "Africa" 465 | }, 466 | { 467 | "name": "Mexico", 468 | "continent": "America" 469 | }, 470 | { 471 | "name": "Micronesia", 472 | "continent": "Oceania" 473 | }, 474 | { 475 | "name": "Moldova", 476 | "continent": "Europe" 477 | }, 478 | { 479 | "name": "Monaco", 480 | "continent": "Europe" 481 | }, 482 | { 483 | "name": "Mongolia", 484 | "continent": "Asia" 485 | }, 486 | { 487 | "name": "Montenegro", 488 | "continent": "Europe" 489 | }, 490 | { 491 | "name": "Morocco", 492 | "continent": "Africa" 493 | }, 494 | { 495 | "name": "Mozambique", 496 | "continent": "Africa" 497 | }, 498 | { 499 | "name": "Namibia", 500 | "continent": "Africa" 501 | }, 502 | { 503 | "name": "Nauru", 504 | "continent": "Oceania" 505 | }, 506 | { 507 | "name": "Nepal", 508 | "continent": "Asia" 509 | }, 510 | { 511 | "name": "Netherlands", 512 | "continent": "Europe" 513 | }, 514 | { 515 | "name": "New Zealand", 516 | "continent": "Oceania" 517 | }, 518 | { 519 | "name": "Nicaragua", 520 | "continent": "America" 521 | }, 522 | { 523 | "name": "Niger", 524 | "continent": "Africa" 525 | }, 526 | { 527 | "name": "Nigeria", 528 | "continent": "Africa" 529 | }, 530 | { 531 | "name": "Norway", 532 | "continent": "Europe" 533 | }, 534 | { 535 | "name": "Oman", 536 | "continent": "Asia" 537 | }, 538 | { 539 | "name": "Pakistan", 540 | "continent": "Asia" 541 | }, 542 | { 543 | "name": "Palau", 544 | "continent": "Oceania" 545 | }, 546 | { 547 | "name": "Panama", 548 | "continent": "America" 549 | }, 550 | { 551 | "name": "Papua New Guinea", 552 | "continent": "Oceania" 553 | }, 554 | { 555 | "name": "Paraguay", 556 | "continent": "America" 557 | }, 558 | { 559 | "name": "Peru", 560 | "continent": "America" 561 | }, 562 | { 563 | "name": "Philippines", 564 | "continent": "Asia" 565 | }, 566 | { 567 | "name": "Poland", 568 | "continent": "Europe" 569 | }, 570 | { 571 | "name": "Portugal", 572 | "continent": "Europe" 573 | }, 574 | { 575 | "name": "Puerto Rico", 576 | "continent": "America" 577 | }, 578 | { 579 | "name": "Qatar", 580 | "continent": "Asia" 581 | }, 582 | { 583 | "name": "Romania", 584 | "continent": "Europe" 585 | }, 586 | { 587 | "name": "Russia", 588 | "continent": "Europe" 589 | }, 590 | { 591 | "name": "Rwanda", 592 | "continent": "Africa" 593 | }, 594 | { 595 | "name": "Saint Kitts and Nevis", 596 | "continent": "America" 597 | }, 598 | { 599 | "name": "Saint Lucia", 600 | "continent": "America" 601 | }, 602 | { 603 | "name": "Saint Vincent and the Grenadines", 604 | "continent": "America" 605 | }, 606 | { 607 | "name": "Samoa", 608 | "continent": "Oceania" 609 | }, 610 | { 611 | "name": "San Marino", 612 | "continent": "Europe" 613 | }, 614 | { 615 | "name": "Saudi Arabia", 616 | "continent": "Asia" 617 | }, 618 | { 619 | "name": "Scotland", 620 | "continent": "Europe" 621 | }, 622 | { 623 | "name": "Senegal", 624 | "continent": "Africa" 625 | }, 626 | { 627 | "name": "Serbia", 628 | "continent": "Europe" 629 | }, 630 | { 631 | "name": "Seychelles", 632 | "continent": "Africa" 633 | }, 634 | { 635 | "name": "Sierra Leone", 636 | "continent": "Africa" 637 | }, 638 | { 639 | "name": "Singapore", 640 | "continent": "Asia" 641 | }, 642 | { 643 | "name": "Slovakia", 644 | "continent": "Europe" 645 | }, 646 | { 647 | "name": "Slovenia", 648 | "continent": "Europe" 649 | }, 650 | { 651 | "name": "Solomon Islands", 652 | "continent": "Oceania" 653 | }, 654 | { 655 | "name": "Somalia", 656 | "continent": "Africa" 657 | }, 658 | { 659 | "name": "South Africa", 660 | "continent": "Africa" 661 | }, 662 | { 663 | "name": "Spain", 664 | "continent": "Europe" 665 | }, 666 | { 667 | "name": "Sri Lanka", 668 | "continent": "Asia" 669 | }, 670 | { 671 | "name": "Sudan", 672 | "continent": "Africa" 673 | }, 674 | { 675 | "name": "Suriname", 676 | "continent": "America" 677 | }, 678 | { 679 | "name": "Swaziland", 680 | "continent": "Africa" 681 | }, 682 | { 683 | "name": "Sweden", 684 | "continent": "Europe" 685 | }, 686 | { 687 | "name": "Switzerland", 688 | "continent": "Europe" 689 | }, 690 | { 691 | "name": "Syria", 692 | "continent": "Asia" 693 | }, 694 | { 695 | "name": "Taiwan", 696 | "continent": "Asia" 697 | }, 698 | { 699 | "name": "Tajikistan", 700 | "continent": "Asia" 701 | }, 702 | { 703 | "name": "Tanzania", 704 | "continent": "Africa" 705 | }, 706 | { 707 | "name": "Thailand", 708 | "continent": "Asia" 709 | }, 710 | { 711 | "name": "Togo", 712 | "continent": "Africa" 713 | }, 714 | { 715 | "name": "Tonga", 716 | "continent": "Oceania" 717 | }, 718 | { 719 | "name": "Trinidad and Tobago", 720 | "continent": "America" 721 | }, 722 | { 723 | "name": "Tunisia", 724 | "continent": "Africa" 725 | }, 726 | { 727 | "name": "Turkey", 728 | "continent": "Asia" 729 | }, 730 | { 731 | "name": "Turkmenistan", 732 | "continent": "Asia" 733 | }, 734 | { 735 | "name": "Tuvalu", 736 | "continent": "Oceania" 737 | }, 738 | { 739 | "name": "Uganda", 740 | "continent": "Africa" 741 | }, 742 | { 743 | "name": "Ukraine", 744 | "continent": "Europe" 745 | }, 746 | { 747 | "name": "United Arab Emirates", 748 | "continent": "Asia" 749 | }, 750 | { 751 | "name": "United Kingdom", 752 | "continent": "Europe" 753 | }, 754 | { 755 | "name": "United States of America", 756 | "continent": "America" 757 | }, 758 | { 759 | "name": "Uruguay", 760 | "continent": "America" 761 | }, 762 | { 763 | "name": "USSR", 764 | "continent": "Europe" 765 | }, 766 | { 767 | "name": "Uzbekistan", 768 | "continent": "Asia" 769 | }, 770 | { 771 | "name": "Vanuatu", 772 | "continent": "Oceania" 773 | }, 774 | { 775 | "name": "Vatican City", 776 | "continent": "Europe" 777 | }, 778 | { 779 | "name": "Venezuela", 780 | "continent": "America" 781 | }, 782 | { 783 | "name": "Vietnam", 784 | "continent": "Asia" 785 | }, 786 | { 787 | "name": "Wales", 788 | "continent": "Europe" 789 | }, 790 | { 791 | "name": "Yemen", 792 | "continent": "Asia" 793 | }, 794 | { 795 | "name": "Zambia", 796 | "continent": "Africa" 797 | }, 798 | { 799 | "name": "Zimbabwe", 800 | "continent": "Africa" 801 | } 802 | ] 803 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/app/index.js: -------------------------------------------------------------------------------- 1 | import './router.config'; 2 | 3 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/app/router.config.js: -------------------------------------------------------------------------------- 1 | import { Visualizer } from '@uirouter/visualizer'; 2 | import { DSRPlugin } from '@uirouter/dsr'; 3 | 4 | import { APP_MODULE } from './app.module'; 5 | import { getContinents, getCountries } from './data.api'; 6 | 7 | import './about.component'; 8 | import './continentList.component'; 9 | import './countryDetail.component'; 10 | import './countryList.component'; 11 | 12 | export const states = [ 13 | { 14 | name: 'continentlist', 15 | url: '/continents', 16 | dsr: true, 17 | component: 'continentList', 18 | resolve: { 19 | 'continents': () => getContinents(), 20 | }, 21 | }, 22 | 23 | { 24 | name: 'continentlist.countrylist', 25 | url: '/:continent', 26 | component: 'countryList', 27 | resolve: { 28 | 'countries': ($transition$) => getCountries($transition$.params().continent), 29 | }, 30 | }, 31 | 32 | { 33 | name: 'continentlist.countrylist.countrydetail', 34 | url: '/:country', 35 | component: 'countryDetail', 36 | resolve: { 37 | 'country': ($transition$) => $transition$.params().country, 38 | }, 39 | }, 40 | 41 | { 42 | name: 'about', 43 | url: '/about', 44 | component: 'about', 45 | }, 46 | ]; 47 | 48 | APP_MODULE.config(function ($uiRouterProvider) { 49 | $uiRouterProvider.plugin(DSRPlugin); 50 | $uiRouterProvider.plugin(Visualizer); 51 | 52 | // Add states 53 | states.forEach(state => $uiRouterProvider.stateRegistry.register(state)); 54 | 55 | // Set initial state 56 | $uiRouterProvider.urlService.rules.initial({ state: 'about' }); 57 | }); 58 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:4000", 3 | "video": false 4 | } 5 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/cypress/integration/example_spec.js: -------------------------------------------------------------------------------- 1 | describe('example app', () => { 2 | it('loads', () => { 3 | cy.visit(''); 4 | }); 5 | 6 | it('renders links', () => { 7 | cy.visit('/'); 8 | cy.get('a').contains('about'); 9 | cy.get('a').contains('continentlist'); 10 | }); 11 | 12 | it('renders about by default', () => { 13 | cy.visit('/'); 14 | cy.contains('This is a trivial Deep State Redirect example app'); 15 | }); 16 | 17 | it('can navigate to continentlist', () => { 18 | cy.visit(''); 19 | cy 20 | .get('a') 21 | .contains('continentlist') 22 | .click(); 23 | 24 | cy.contains('Africa'); 25 | cy.contains('America'); 26 | cy.contains('Oceania'); 27 | }); 28 | 29 | it('can navigate to belize', () => { 30 | cy.visit(''); 31 | cy 32 | .get('a') 33 | .contains('continentlist') 34 | .click(); 35 | cy 36 | .get('a') 37 | .contains('America') 38 | .click(); 39 | cy 40 | .get('a') 41 | .contains('Belize') 42 | .click(); 43 | cy.get('h3').contains('Belize'); 44 | }); 45 | 46 | it('can navigate to belize and back', () => { 47 | cy.visit(''); 48 | cy 49 | .get('a') 50 | .contains('continentlist') 51 | .click(); 52 | cy 53 | .get('a') 54 | .contains('America') 55 | .click(); 56 | cy.url().should('include', '/America'); 57 | 58 | cy 59 | .get('a') 60 | .contains('Belize') 61 | .click(); 62 | cy.get('h3').contains('Belize'); 63 | cy.url().should('include', '/America/Belize'); 64 | 65 | cy 66 | .get('a') 67 | .contains('about') 68 | .click(); 69 | cy.contains('This is a trivial Deep State Redirect example app'); 70 | }); 71 | 72 | it('dsr sends you back to belize', () => { 73 | cy.visit(''); 74 | cy 75 | .get('a') 76 | .contains('continentlist') 77 | .click(); 78 | cy 79 | .get('a') 80 | .contains('America') 81 | .click(); 82 | cy.url().should('include', '/America'); 83 | 84 | cy 85 | .get('a') 86 | .contains('Belize') 87 | .click(); 88 | cy.url().should('include', '/America/Belize'); 89 | cy.get('h3').contains('Belize'); 90 | 91 | cy 92 | .get('a') 93 | .contains('about') 94 | .click(); 95 | cy.url().should('include', '/about'); 96 | cy.contains('This is a trivial Deep State Redirect example app'); 97 | 98 | cy 99 | .get('a') 100 | .contains('continentlist') 101 | .click(); 102 | cy.url().should('include', '/America/Belize'); 103 | cy.get('h3').contains('Belize'); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | about 9 | continentlist 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/index.js: -------------------------------------------------------------------------------- 1 | import './app/index'; 2 | 3 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-webpack", 3 | "version": "1.0.0", 4 | "description": "AngularJS/webpack sticky states example", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "npm run build && cypress-runner run --path .", 8 | "test:open": "npm run build && cypress-runner open --path .", 9 | "build": "webpack --progress", 10 | "start": "webpack-dev-server --progress --open" 11 | }, 12 | "author": "", 13 | "license": "MIT", 14 | "dependencies": { 15 | "@uirouter/angularjs": "^1.0.13", 16 | "@uirouter/dsr": "^1.0.2", 17 | "@uirouter/visualizer": "^5.1.3", 18 | "angular": "^1.6.8" 19 | }, 20 | "devDependencies": { 21 | "@uirouter/cypress-runner": "^1.0.2", 22 | "babel-core": "^6.26.0", 23 | "babel-loader": "^7.1.2", 24 | "webpack": "^3.10.0", 25 | "webpack-dev-server": "^2.10.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/styles.css: -------------------------------------------------------------------------------- 1 | .active { 2 | font-weight: bold; 3 | } 4 | .container { 5 | display: flex; 6 | flex-flow: row wrap; 7 | } 8 | .container > * { 9 | border: 1px solid; 10 | padding: 0.5em; 11 | margin: 0.5em; 12 | flex: 1 1 75px; 13 | } 14 | .container > a.active { 15 | background: lightgray; 16 | } 17 | -------------------------------------------------------------------------------- /examples/angularjs-webpack/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: "./index.js", 3 | output: { 4 | filename: "bundle.js", 5 | }, 6 | module: { 7 | loaders: [ { test: /\.js?$/, loader: "babel-loader", } ] 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /examples/create-react-app/README.md: -------------------------------------------------------------------------------- 1 | # create-react-app 2 | 3 | Example showing sticky states installed in a create-react-app app. 4 | 5 | ## Running 6 | 7 | ``` 8 | yarn install 9 | yarn start 10 | ``` 11 | -------------------------------------------------------------------------------- /examples/create-react-app/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:4000", 3 | "video": false 4 | } 5 | -------------------------------------------------------------------------------- /examples/create-react-app/cypress/integration/example_spec.js: -------------------------------------------------------------------------------- 1 | describe('example app', () => { 2 | it('loads', () => { 3 | cy.visit(''); 4 | }); 5 | 6 | it('renders links', () => { 7 | cy.visit('/'); 8 | cy.get('a').contains('about'); 9 | cy.get('a').contains('continentlist'); 10 | }); 11 | 12 | it('renders about by default', () => { 13 | cy.visit('/'); 14 | cy.contains('This is a trivial Deep State Redirect example app'); 15 | }); 16 | 17 | it('can navigate to continentlist', () => { 18 | cy.visit(''); 19 | cy 20 | .get('a') 21 | .contains('continentlist') 22 | .click(); 23 | 24 | cy.contains('Africa'); 25 | cy.contains('America'); 26 | cy.contains('Oceania'); 27 | }); 28 | 29 | it('can navigate to belize', () => { 30 | cy.visit(''); 31 | cy 32 | .get('a') 33 | .contains('continentlist') 34 | .click(); 35 | cy 36 | .get('a') 37 | .contains('America') 38 | .click(); 39 | cy 40 | .get('a') 41 | .contains('Belize') 42 | .click(); 43 | cy.get('h3').contains('Belize'); 44 | }); 45 | 46 | it('can navigate to belize and back', () => { 47 | cy.visit(''); 48 | cy 49 | .get('a') 50 | .contains('continentlist') 51 | .click(); 52 | cy 53 | .get('a') 54 | .contains('America') 55 | .click(); 56 | cy.url().should('include', '/America'); 57 | 58 | cy 59 | .get('a') 60 | .contains('Belize') 61 | .click(); 62 | cy.get('h3').contains('Belize'); 63 | cy.url().should('include', '/America/Belize'); 64 | 65 | cy 66 | .get('a') 67 | .contains('about') 68 | .click(); 69 | cy.contains('This is a trivial Deep State Redirect example app'); 70 | }); 71 | 72 | it('dsr sends you back to belize', () => { 73 | cy.visit(''); 74 | cy 75 | .get('a') 76 | .contains('continentlist') 77 | .click(); 78 | cy 79 | .get('a') 80 | .contains('America') 81 | .click(); 82 | cy.url().should('include', '/America'); 83 | 84 | cy 85 | .get('a') 86 | .contains('Belize') 87 | .click(); 88 | cy.url().should('include', '/America/Belize'); 89 | cy.get('h3').contains('Belize'); 90 | 91 | cy 92 | .get('a') 93 | .contains('about') 94 | .click(); 95 | cy.url().should('include', '/about'); 96 | cy.contains('This is a trivial Deep State Redirect example app'); 97 | 98 | cy 99 | .get('a') 100 | .contains('continentlist') 101 | .click(); 102 | cy.url().should('include', '/America/Belize'); 103 | cy.get('h3').contains('Belize'); 104 | }); 105 | }); 106 | -------------------------------------------------------------------------------- /examples/create-react-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create-react-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@uirouter/react": "^0.6.2", 7 | "@uirouter/dsr": "^1.0.2", 8 | "@uirouter/visualizer": "^6.0.0", 9 | "react": "^16.2.0", 10 | "react-dom": "^16.2.0" 11 | }, 12 | "devDependencies": { 13 | "@uirouter/cypress-runner": "^1.0.2", 14 | "react-scripts": "1.1.1" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "npm run build && cypress-runner run --path build", 20 | "test:open": "npm run build && cypress-runner open --path build", 21 | "eject": "react-scripts eject" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/create-react-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ui-router/dsr/faf4ac097655375f2d1804ef706b3836b73597d3/examples/create-react-app/public/favicon.ico -------------------------------------------------------------------------------- /examples/create-react-app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /examples/create-react-app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/create-react-app/src/About.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { UISref } from '@uirouter/react'; 3 | 4 | export class About extends React.Component { 5 | render() { 6 | return ( 7 |
8 |

This is a trivial Deep State Redirect example app

9 |
    10 |
  1. Active the continentlist state
  2. 11 |
  3. Select a continent
  4. 12 |
  5. Select a country
  6. 13 |
  7. Reactivate this state (about)
  8. 14 |
  9. 15 | Active the continents state again.
    16 | You are redirected to the previously active substate of 17 | continentlist (including parameters).
    18 | You should see the country you chose in the previous step. 19 |
  10. 20 |
21 |
22 | ); 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /examples/create-react-app/src/App.css: -------------------------------------------------------------------------------- 1 | .active { 2 | font-weight: bold; 3 | } 4 | .container { 5 | display: flex; 6 | flex-flow: row wrap; 7 | } 8 | .container > * { 9 | border: 1px solid; 10 | padding: 0.5em; 11 | margin: 0.5em; 12 | flex: 1 1 75px; 13 | } 14 | .container > a.active { 15 | background: lightgray; 16 | } 17 | -------------------------------------------------------------------------------- /examples/create-react-app/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { UIRouter, UISref, UISrefActive, UIView } from '@uirouter/react'; 3 | import { pushStateLocationPlugin } from '@uirouter/core'; 4 | import { Visualizer } from '@uirouter/visualizer'; 5 | import { DSRPlugin } from "@uirouter/dsr"; 6 | 7 | import { ContinentList } from "./ContinentList"; 8 | import { CountryList } from "./CountryList"; 9 | import { About } from "./About"; 10 | import { CountryDetail } from "./CountryDetail"; 11 | 12 | import { getContinents, getCountries } from "./data.api"; 13 | 14 | import './App.css'; 15 | 16 | const plugins = [ 17 | pushStateLocationPlugin, 18 | Visualizer, 19 | DSRPlugin, 20 | ]; 21 | 22 | export const states = [ 23 | { 24 | name: 'continentlist', 25 | url: '/continents', 26 | dsr: true, 27 | component: ContinentList, 28 | resolve: { 29 | 'continents': () => getContinents(), 30 | }, 31 | }, 32 | 33 | { 34 | name: 'continentlist.countrylist', 35 | url: '/:continent', 36 | component: CountryList, 37 | resolve: { 38 | 'countries': ['$transition$', ($transition$) => getCountries($transition$.params().continent)], 39 | }, 40 | }, 41 | 42 | { 43 | name: 'continentlist.countrylist.countrydetail', 44 | url: '/:country', 45 | component: CountryDetail, 46 | resolve: { 47 | 'country': ['$transition$', ($transition$) => $transition$.params().country], 48 | }, 49 | }, 50 | 51 | { 52 | name: 'about', 53 | url: '/about', 54 | component: About, 55 | }, 56 | ]; 57 | 58 | function routerConfig(router) { 59 | // Set initial state 60 | router.urlService.rules.initial({ state: 'about' }); 61 | } 62 | 63 | class App extends Component { 64 | render() { 65 | return ( 66 | 67 |
68 | 69 | about 70 | 71 | 72 | 73 | continentlist 74 | 75 | 76 | 77 |
78 |
79 | ); 80 | } 81 | } 82 | 83 | export default App; 84 | -------------------------------------------------------------------------------- /examples/create-react-app/src/ContinentList.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { UISref, UISrefActive, UIView } from '@uirouter/react'; 3 | 4 | export class ContinentList extends React.Component { 5 | render() { 6 | const { continents } = this.props; 7 | return ( 8 |
9 |

Continents

10 | 11 | {continents.map(continent => { 12 | return ( 13 | 14 | 15 | 16 | {continent} 17 | 18 | 19 | 20 | ); 21 | })} 22 | 23 | 24 |
25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /examples/create-react-app/src/CountryDetail.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export class CountryDetail extends React.Component { 4 | render() { 5 | const { country } = this.props; 6 | if (!country) return null; 7 | 8 | const prefix = '//www.randomlists.com/img/national-flags/'; 9 | const imageName = country.toLowerCase().replace(/ /g, '_'); 10 | const imgSrc = `${prefix}${imageName}.gif`; 11 | const alt = `flag of ${country}}`; 12 | 13 | return ( 14 |
15 |

{country}

16 |
17 | {alt}/ 18 |
19 |
20 | ) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/create-react-app/src/CountryList.jsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { UISref, UISrefActive, UIView } from '@uirouter/react'; 3 | 4 | export class CountryList extends React.Component { 5 | render() { 6 | const { countries } = this.props; 7 | 8 | return ( 9 |
10 | 11 | 12 |
13 | 14 | {countries.map(country => { 15 | return ( 16 | 17 | 18 | {country} 19 | 20 | 21 | ) 22 | })} 23 |
24 |
25 | ); 26 | } 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /examples/create-react-app/src/data.api.js: -------------------------------------------------------------------------------- 1 | function getContinents() { 2 | return Promise.resolve(require('./data.json')) 3 | .then(countries => countries.map(country => country.continent)) 4 | .then(continents => continents.reduce((acc, continent) => acc.includes(continent) ? acc : acc.concat(continent), [])) 5 | } 6 | 7 | function getCountries(continent) { 8 | return Promise.resolve(require('./data.json')) 9 | .then(countries => countries.filter(country => country.continent === continent)) 10 | .then(countries => countries.map(country => country.name)); 11 | } 12 | 13 | export { getContinents, getCountries }; 14 | -------------------------------------------------------------------------------- /examples/create-react-app/src/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Afghanistan", 4 | "continent": "Asia" 5 | }, 6 | { 7 | "name": "Albania", 8 | "continent": "Europe" 9 | }, 10 | { 11 | "name": "Algeria", 12 | "continent": "Africa" 13 | }, 14 | { 15 | "name": "Andorra", 16 | "continent": "Europe" 17 | }, 18 | { 19 | "name": "Angola", 20 | "continent": "Africa" 21 | }, 22 | { 23 | "name": "Antigua and Barbuda", 24 | "continent": "America" 25 | }, 26 | { 27 | "name": "Argentina", 28 | "continent": "America" 29 | }, 30 | { 31 | "name": "Armenia", 32 | "continent": "Asia" 33 | }, 34 | { 35 | "name": "Australia", 36 | "continent": "Oceania" 37 | }, 38 | { 39 | "name": "Austria", 40 | "continent": "Europe" 41 | }, 42 | { 43 | "name": "Azerbaijan", 44 | "continent": "Asia" 45 | }, 46 | { 47 | "name": "Bahamas", 48 | "continent": "America" 49 | }, 50 | { 51 | "name": "Bahrain", 52 | "continent": "Asia" 53 | }, 54 | { 55 | "name": "Bangladesh", 56 | "continent": "Asia" 57 | }, 58 | { 59 | "name": "Barbados", 60 | "continent": "America" 61 | }, 62 | { 63 | "name": "Belarus", 64 | "continent": "Europe" 65 | }, 66 | { 67 | "name": "Belgium", 68 | "continent": "Europe" 69 | }, 70 | { 71 | "name": "Belize", 72 | "continent": "America" 73 | }, 74 | { 75 | "name": "Benin", 76 | "continent": "Africa" 77 | }, 78 | { 79 | "name": "Bhutan", 80 | "continent": "Asia" 81 | }, 82 | { 83 | "name": "Bolivia", 84 | "continent": "America" 85 | }, 86 | { 87 | "name": "Bosnia and Herzegovina", 88 | "continent": "Europe" 89 | }, 90 | { 91 | "name": "Botswana", 92 | "continent": "Africa" 93 | }, 94 | { 95 | "name": "Brazil", 96 | "continent": "America" 97 | }, 98 | { 99 | "name": "Brunei", 100 | "continent": "Asia" 101 | }, 102 | { 103 | "name": "Bulgaria", 104 | "continent": "Europe" 105 | }, 106 | { 107 | "name": "Burkina Faso", 108 | "continent": "Africa" 109 | }, 110 | { 111 | "name": "Myanmar", 112 | "continent": "Asia" 113 | }, 114 | { 115 | "name": "Burundi", 116 | "continent": "Africa" 117 | }, 118 | { 119 | "name": "Cambodia", 120 | "continent": "Asia" 121 | }, 122 | { 123 | "name": "Cameroon", 124 | "continent": "Africa" 125 | }, 126 | { 127 | "name": "Canada", 128 | "continent": "America" 129 | }, 130 | { 131 | "name": "Cape Verde", 132 | "continent": "Africa" 133 | }, 134 | { 135 | "name": "Central African Republic", 136 | "continent": "Africa" 137 | }, 138 | { 139 | "name": "Chad", 140 | "continent": "Africa" 141 | }, 142 | { 143 | "name": "Chile", 144 | "continent": "America" 145 | }, 146 | { 147 | "name": "China", 148 | "continent": "Asia" 149 | }, 150 | { 151 | "name": "Colombia", 152 | "continent": "America" 153 | }, 154 | { 155 | "name": "Comoros", 156 | "continent": "Africa" 157 | }, 158 | { 159 | "name": "Congo", 160 | "continent": "Africa" 161 | }, 162 | { 163 | "name": "Costa Rica", 164 | "continent": "America" 165 | }, 166 | { 167 | "name": "Croatia", 168 | "continent": "Europe" 169 | }, 170 | { 171 | "name": "Cuba", 172 | "continent": "America" 173 | }, 174 | { 175 | "name": "Cyprus", 176 | "continent": "Europe" 177 | }, 178 | { 179 | "name": "Czech Republic", 180 | "continent": "Europe" 181 | }, 182 | { 183 | "name": "Denmark", 184 | "continent": "Europe" 185 | }, 186 | { 187 | "name": "Djibouti", 188 | "continent": "Africa" 189 | }, 190 | { 191 | "name": "Dominica", 192 | "continent": "America" 193 | }, 194 | { 195 | "name": "Dominican Republic", 196 | "continent": "America" 197 | }, 198 | { 199 | "name": "East Timor", 200 | "continent": "Asia" 201 | }, 202 | { 203 | "name": "Ecuador", 204 | "continent": "America" 205 | }, 206 | { 207 | "name": "Egypt", 208 | "continent": "Africa" 209 | }, 210 | { 211 | "name": "El Salvador", 212 | "continent": "America" 213 | }, 214 | { 215 | "name": "England", 216 | "continent": "Europe" 217 | }, 218 | { 219 | "name": "Equatorial Guinea", 220 | "continent": "Africa" 221 | }, 222 | { 223 | "name": "Eritrea", 224 | "continent": "Africa" 225 | }, 226 | { 227 | "name": "Estonia", 228 | "continent": "Europe" 229 | }, 230 | { 231 | "name": "Ethiopia", 232 | "continent": "Africa" 233 | }, 234 | { 235 | "name": "Fiji", 236 | "continent": "Oceania" 237 | }, 238 | { 239 | "name": "Finland", 240 | "continent": "Europe" 241 | }, 242 | { 243 | "name": "France", 244 | "continent": "Europe" 245 | }, 246 | { 247 | "name": "Gabon", 248 | "continent": "Africa" 249 | }, 250 | { 251 | "name": "Gambia", 252 | "continent": "Africa" 253 | }, 254 | { 255 | "name": "Georgia", 256 | "continent": "Asia" 257 | }, 258 | { 259 | "name": "Germany", 260 | "continent": "Europe" 261 | }, 262 | { 263 | "name": "Ghana", 264 | "continent": "Africa" 265 | }, 266 | { 267 | "name": "Greece", 268 | "continent": "Europe" 269 | }, 270 | { 271 | "name": "Grenada", 272 | "continent": "America" 273 | }, 274 | { 275 | "name": "Guatemala", 276 | "continent": "America" 277 | }, 278 | { 279 | "name": "Guinea", 280 | "continent": "Africa" 281 | }, 282 | { 283 | "name": "Guinea-Bissau", 284 | "continent": "Africa" 285 | }, 286 | { 287 | "name": "Guyana", 288 | "continent": "America" 289 | }, 290 | { 291 | "name": "Haiti", 292 | "continent": "America" 293 | }, 294 | { 295 | "name": "Honduras", 296 | "continent": "America" 297 | }, 298 | { 299 | "name": "Hong Kong", 300 | "continent": "Asia" 301 | }, 302 | { 303 | "name": "Hungary", 304 | "continent": "Europe" 305 | }, 306 | { 307 | "name": "Iceland", 308 | "continent": "Europe" 309 | }, 310 | { 311 | "name": "India", 312 | "continent": "Asia" 313 | }, 314 | { 315 | "name": "Indonesia", 316 | "continent": "Asia" 317 | }, 318 | { 319 | "name": "Iran", 320 | "continent": "Asia" 321 | }, 322 | { 323 | "name": "Iraq", 324 | "continent": "Asia" 325 | }, 326 | { 327 | "name": "Ireland", 328 | "continent": "Europe" 329 | }, 330 | { 331 | "name": "Isle of Man", 332 | "continent": "Europe" 333 | }, 334 | { 335 | "name": "Israel", 336 | "continent": "Asia" 337 | }, 338 | { 339 | "name": "Italy", 340 | "continent": "Europe" 341 | }, 342 | { 343 | "name": "Jamaica", 344 | "continent": "America" 345 | }, 346 | { 347 | "name": "Japan", 348 | "continent": "Asia" 349 | }, 350 | { 351 | "name": "Jordan", 352 | "continent": "Asia" 353 | }, 354 | { 355 | "name": "Kazakhstan", 356 | "continent": "Asia" 357 | }, 358 | { 359 | "name": "Kenya", 360 | "continent": "Africa" 361 | }, 362 | { 363 | "name": "Kiribati", 364 | "continent": "Oceania" 365 | }, 366 | { 367 | "name": "North Korea", 368 | "continent": "Asia" 369 | }, 370 | { 371 | "name": "South Korea", 372 | "continent": "Asia" 373 | }, 374 | { 375 | "name": "Kosovo", 376 | "continent": "Europe" 377 | }, 378 | { 379 | "name": "Kuwait", 380 | "continent": "Asia" 381 | }, 382 | { 383 | "name": "Kyrgyzstan", 384 | "continent": "Asia" 385 | }, 386 | { 387 | "name": "Laos", 388 | "continent": "Asia" 389 | }, 390 | { 391 | "name": "Latvia", 392 | "continent": "Europe" 393 | }, 394 | { 395 | "name": "Lebanon", 396 | "continent": "Asia" 397 | }, 398 | { 399 | "name": "Lesotho", 400 | "continent": "Africa" 401 | }, 402 | { 403 | "name": "Liberia", 404 | "continent": "Africa" 405 | }, 406 | { 407 | "name": "Libya", 408 | "continent": "Africa" 409 | }, 410 | { 411 | "name": "Liechtenstein", 412 | "continent": "Europe" 413 | }, 414 | { 415 | "name": "Lithuania", 416 | "continent": "Europe" 417 | }, 418 | { 419 | "name": "Luxembourg", 420 | "continent": "Europe" 421 | }, 422 | { 423 | "name": "Macau", 424 | "continent": "Asia" 425 | }, 426 | { 427 | "name": "Macedonia", 428 | "continent": "Europe" 429 | }, 430 | { 431 | "name": "Madagascar", 432 | "continent": "Africa" 433 | }, 434 | { 435 | "name": "Malawi", 436 | "continent": "Africa" 437 | }, 438 | { 439 | "name": "Malaysia", 440 | "continent": "Asia" 441 | }, 442 | { 443 | "name": "Maldives", 444 | "continent": "Asia" 445 | }, 446 | { 447 | "name": "Mali", 448 | "continent": "Africa" 449 | }, 450 | { 451 | "name": "Malta", 452 | "continent": "Europe" 453 | }, 454 | { 455 | "name": "Marshall Islands", 456 | "continent": "Oceania" 457 | }, 458 | { 459 | "name": "Mauritania", 460 | "continent": "Africa" 461 | }, 462 | { 463 | "name": "Mauritius", 464 | "continent": "Africa" 465 | }, 466 | { 467 | "name": "Mexico", 468 | "continent": "America" 469 | }, 470 | { 471 | "name": "Micronesia", 472 | "continent": "Oceania" 473 | }, 474 | { 475 | "name": "Moldova", 476 | "continent": "Europe" 477 | }, 478 | { 479 | "name": "Monaco", 480 | "continent": "Europe" 481 | }, 482 | { 483 | "name": "Mongolia", 484 | "continent": "Asia" 485 | }, 486 | { 487 | "name": "Montenegro", 488 | "continent": "Europe" 489 | }, 490 | { 491 | "name": "Morocco", 492 | "continent": "Africa" 493 | }, 494 | { 495 | "name": "Mozambique", 496 | "continent": "Africa" 497 | }, 498 | { 499 | "name": "Namibia", 500 | "continent": "Africa" 501 | }, 502 | { 503 | "name": "Nauru", 504 | "continent": "Oceania" 505 | }, 506 | { 507 | "name": "Nepal", 508 | "continent": "Asia" 509 | }, 510 | { 511 | "name": "Netherlands", 512 | "continent": "Europe" 513 | }, 514 | { 515 | "name": "New Zealand", 516 | "continent": "Oceania" 517 | }, 518 | { 519 | "name": "Nicaragua", 520 | "continent": "America" 521 | }, 522 | { 523 | "name": "Niger", 524 | "continent": "Africa" 525 | }, 526 | { 527 | "name": "Nigeria", 528 | "continent": "Africa" 529 | }, 530 | { 531 | "name": "Norway", 532 | "continent": "Europe" 533 | }, 534 | { 535 | "name": "Oman", 536 | "continent": "Asia" 537 | }, 538 | { 539 | "name": "Pakistan", 540 | "continent": "Asia" 541 | }, 542 | { 543 | "name": "Palau", 544 | "continent": "Oceania" 545 | }, 546 | { 547 | "name": "Panama", 548 | "continent": "America" 549 | }, 550 | { 551 | "name": "Papua New Guinea", 552 | "continent": "Oceania" 553 | }, 554 | { 555 | "name": "Paraguay", 556 | "continent": "America" 557 | }, 558 | { 559 | "name": "Peru", 560 | "continent": "America" 561 | }, 562 | { 563 | "name": "Philippines", 564 | "continent": "Asia" 565 | }, 566 | { 567 | "name": "Poland", 568 | "continent": "Europe" 569 | }, 570 | { 571 | "name": "Portugal", 572 | "continent": "Europe" 573 | }, 574 | { 575 | "name": "Puerto Rico", 576 | "continent": "America" 577 | }, 578 | { 579 | "name": "Qatar", 580 | "continent": "Asia" 581 | }, 582 | { 583 | "name": "Romania", 584 | "continent": "Europe" 585 | }, 586 | { 587 | "name": "Russia", 588 | "continent": "Europe" 589 | }, 590 | { 591 | "name": "Rwanda", 592 | "continent": "Africa" 593 | }, 594 | { 595 | "name": "Saint Kitts and Nevis", 596 | "continent": "America" 597 | }, 598 | { 599 | "name": "Saint Lucia", 600 | "continent": "America" 601 | }, 602 | { 603 | "name": "Saint Vincent and the Grenadines", 604 | "continent": "America" 605 | }, 606 | { 607 | "name": "Samoa", 608 | "continent": "Oceania" 609 | }, 610 | { 611 | "name": "San Marino", 612 | "continent": "Europe" 613 | }, 614 | { 615 | "name": "Saudi Arabia", 616 | "continent": "Asia" 617 | }, 618 | { 619 | "name": "Scotland", 620 | "continent": "Europe" 621 | }, 622 | { 623 | "name": "Senegal", 624 | "continent": "Africa" 625 | }, 626 | { 627 | "name": "Serbia", 628 | "continent": "Europe" 629 | }, 630 | { 631 | "name": "Seychelles", 632 | "continent": "Africa" 633 | }, 634 | { 635 | "name": "Sierra Leone", 636 | "continent": "Africa" 637 | }, 638 | { 639 | "name": "Singapore", 640 | "continent": "Asia" 641 | }, 642 | { 643 | "name": "Slovakia", 644 | "continent": "Europe" 645 | }, 646 | { 647 | "name": "Slovenia", 648 | "continent": "Europe" 649 | }, 650 | { 651 | "name": "Solomon Islands", 652 | "continent": "Oceania" 653 | }, 654 | { 655 | "name": "Somalia", 656 | "continent": "Africa" 657 | }, 658 | { 659 | "name": "South Africa", 660 | "continent": "Africa" 661 | }, 662 | { 663 | "name": "Spain", 664 | "continent": "Europe" 665 | }, 666 | { 667 | "name": "Sri Lanka", 668 | "continent": "Asia" 669 | }, 670 | { 671 | "name": "Sudan", 672 | "continent": "Africa" 673 | }, 674 | { 675 | "name": "Suriname", 676 | "continent": "America" 677 | }, 678 | { 679 | "name": "Swaziland", 680 | "continent": "Africa" 681 | }, 682 | { 683 | "name": "Sweden", 684 | "continent": "Europe" 685 | }, 686 | { 687 | "name": "Switzerland", 688 | "continent": "Europe" 689 | }, 690 | { 691 | "name": "Syria", 692 | "continent": "Asia" 693 | }, 694 | { 695 | "name": "Taiwan", 696 | "continent": "Asia" 697 | }, 698 | { 699 | "name": "Tajikistan", 700 | "continent": "Asia" 701 | }, 702 | { 703 | "name": "Tanzania", 704 | "continent": "Africa" 705 | }, 706 | { 707 | "name": "Thailand", 708 | "continent": "Asia" 709 | }, 710 | { 711 | "name": "Togo", 712 | "continent": "Africa" 713 | }, 714 | { 715 | "name": "Tonga", 716 | "continent": "Oceania" 717 | }, 718 | { 719 | "name": "Trinidad and Tobago", 720 | "continent": "America" 721 | }, 722 | { 723 | "name": "Tunisia", 724 | "continent": "Africa" 725 | }, 726 | { 727 | "name": "Turkey", 728 | "continent": "Asia" 729 | }, 730 | { 731 | "name": "Turkmenistan", 732 | "continent": "Asia" 733 | }, 734 | { 735 | "name": "Tuvalu", 736 | "continent": "Oceania" 737 | }, 738 | { 739 | "name": "Uganda", 740 | "continent": "Africa" 741 | }, 742 | { 743 | "name": "Ukraine", 744 | "continent": "Europe" 745 | }, 746 | { 747 | "name": "United Arab Emirates", 748 | "continent": "Asia" 749 | }, 750 | { 751 | "name": "United Kingdom", 752 | "continent": "Europe" 753 | }, 754 | { 755 | "name": "United States of America", 756 | "continent": "America" 757 | }, 758 | { 759 | "name": "Uruguay", 760 | "continent": "America" 761 | }, 762 | { 763 | "name": "USSR", 764 | "continent": "Europe" 765 | }, 766 | { 767 | "name": "Uzbekistan", 768 | "continent": "Asia" 769 | }, 770 | { 771 | "name": "Vanuatu", 772 | "continent": "Oceania" 773 | }, 774 | { 775 | "name": "Vatican City", 776 | "continent": "Europe" 777 | }, 778 | { 779 | "name": "Venezuela", 780 | "continent": "America" 781 | }, 782 | { 783 | "name": "Vietnam", 784 | "continent": "Asia" 785 | }, 786 | { 787 | "name": "Wales", 788 | "continent": "Europe" 789 | }, 790 | { 791 | "name": "Yemen", 792 | "continent": "Asia" 793 | }, 794 | { 795 | "name": "Zambia", 796 | "continent": "Africa" 797 | }, 798 | { 799 | "name": "Zimbabwe", 800 | "continent": "Africa" 801 | } 802 | ] 803 | -------------------------------------------------------------------------------- /examples/create-react-app/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | ReactDOM.render(React.createElement(App), document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'jsdom', 4 | roots: ['src', 'test'], 5 | testMatch: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)', '**/?*Spec.[jt]s'], 6 | }; 7 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file 2 | var karma = require('karma'); 3 | 4 | module.exports = function(karma) { 5 | var config = { 6 | singleRun: true, 7 | autoWatch: false, 8 | autoWatchInterval: 0, 9 | 10 | // level of logging 11 | // possible values: LOG_DISABLE, LOG_ERROR, LOG_WARN, LOG_INFO, LOG_DEBUG 12 | logLevel: 'warn', 13 | 14 | reporters: ['super-dots', 'mocha'], 15 | colors: true, 16 | mochaReporter: { 17 | output: 'minimal', 18 | }, 19 | 20 | port: 8080, 21 | 22 | // base path, that will be used to resolve files and exclude 23 | basePath: '.', 24 | 25 | browsers: ['ChromeHeadlessNoSandbox'], 26 | customLaunchers: { 27 | ChromeHeadlessNoSandbox: { base: 'ChromeHeadless', flags: ['--no-sandbox'] }, 28 | }, 29 | 30 | frameworks: ['jasmine'], 31 | 32 | plugins: [ 33 | require('karma-webpack'), 34 | require('karma-sourcemap-loader'), 35 | require('karma-super-dots-reporter'), 36 | require('karma-mocha-reporter'), 37 | require('karma-jasmine'), 38 | require('karma-chrome-launcher'), 39 | ], 40 | 41 | webpack: { 42 | mode: 'development', 43 | devtool: 'inline-source-map', 44 | 45 | resolve: { 46 | extensions: ['.js', '.ts'], 47 | }, 48 | 49 | module: { 50 | rules: [{ test: /\.ts$/, use: 'ts-loader' }], 51 | }, 52 | }, 53 | 54 | webpackMiddleware: { 55 | stats: 'minimal', 56 | }, 57 | 58 | files: ['test/index.js'], 59 | 60 | preprocessors: { 61 | 'test/index.js': ['webpack', 'sourcemap'], 62 | }, 63 | }; 64 | 65 | karma.set(config); 66 | }; 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@uirouter/dsr", 3 | "description": "UI-Router Deep State Redirect: redirect to the most recently activated child state", 4 | "version": "1.2.0", 5 | "scripts": { 6 | "clean": "shx rm -rf lib lib-esm _bundles", 7 | "build": "npm run compile && rollup -c && rollup -c --environment MINIFY", 8 | "compile": "npm run clean && tsc && tsc -m es6 --outDir lib-esm", 9 | "test": "jest", 10 | "test:downstream": "test_downstream_projects", 11 | "watch": "run-p watch:*", 12 | "watch:buildjs": "tsc -w", 13 | "watch:test": "jest --watch", 14 | "debug": "node --inspect ./node_modules/.bin/jest --runInBand --watch", 15 | "changelog": "update_changelog", 16 | "release": "release", 17 | "prepublishOnly": "npm run build" 18 | }, 19 | "homepage": "https://ui-router.github.io", 20 | "contributors": [ 21 | { 22 | "name": "Chris Thielen", 23 | "web": "https://github.com/christopherthielen" 24 | } 25 | ], 26 | "maintainers": [ 27 | { 28 | "name": "UIRouter Team", 29 | "web": "https://github.com/ui-router?tab=members" 30 | } 31 | ], 32 | "repository": { 33 | "type": "git", 34 | "url": "https://github.com/ui-router/dsr.git" 35 | }, 36 | "bugs": { 37 | "url": "https://github.com/ui-router/dsr/issues" 38 | }, 39 | "engines": { 40 | "node": ">=4.0.0" 41 | }, 42 | "jsnext:main": "lib-esm/index.js", 43 | "main": "lib/index.js", 44 | "typings": "lib/index.d.ts", 45 | "license": "MIT", 46 | "peerDependencies": { 47 | "@uirouter/core": ">=5.0.0" 48 | }, 49 | "devDependencies": { 50 | "@types/jest": "^26.0.14", 51 | "@types/jquery": "^3.3.38", 52 | "@types/lodash": "^4.14.152", 53 | "@typescript-eslint/eslint-plugin": "^4.1.1", 54 | "@typescript-eslint/parser": "^4.1.1", 55 | "@uirouter/core": "^6.0.5", 56 | "@uirouter/publish-scripts": "^2.5.4", 57 | "bufferutil": "^4.0.1", 58 | "canvas": "^2.5.0", 59 | "eslint": "^7.9.0", 60 | "eslint-config-prettier": "^6.11.0", 61 | "eslint-plugin-prettier": "^3.1.4", 62 | "husky": "^4.2.5", 63 | "jest": "^26.4.2", 64 | "lodash": "^4.17.11", 65 | "prettier": "^2.0.5", 66 | "pretty-quick": "^2.0.1", 67 | "rollup": "^2.10.9", 68 | "rollup-plugin-node-resolve": "^5.2.0", 69 | "rollup-plugin-sourcemaps": "^0.6.2", 70 | "rollup-plugin-uglify": "^6.0.1", 71 | "ts-jest": "^26.4.0", 72 | "typescript": "^3.9.3", 73 | "utf-8-validate": "^5.0.2" 74 | }, 75 | "husky": { 76 | "hooks": { 77 | "pre-commit": "pretty-quick --staged" 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import nodeResolve from 'rollup-plugin-node-resolve'; 2 | import { uglify } from 'rollup-plugin-uglify'; 3 | import sourcemaps from 'rollup-plugin-sourcemaps'; 4 | 5 | var MINIFY = process.env.MINIFY; 6 | 7 | var pkg = require('./package.json'); 8 | var banner = `/** 9 | * ${pkg.description} 10 | * @version v${pkg.version} 11 | * @link ${pkg.homepage} 12 | * @license MIT License, http://www.opensource.org/licenses/MIT 13 | */`; 14 | 15 | var uglifyOpts = { output: {} }; 16 | // retain multiline comment with @license 17 | uglifyOpts.output.comments = (node, comment) => comment.type === 'comment2' && /@license/i.test(comment.value); 18 | 19 | var plugins = [nodeResolve({ jsnext: true }), sourcemaps()]; 20 | 21 | if (MINIFY) plugins.push(uglify(uglifyOpts)); 22 | 23 | var extension = MINIFY ? '.min.js' : '.js'; 24 | 25 | export default { 26 | input: 'lib-esm/index.js', 27 | output: { 28 | name: pkg.name, 29 | globals: { '@uirouter/core': '@uirouter/core' }, 30 | sourcemap: true, 31 | format: 'umd', 32 | exports: 'named', 33 | banner: banner, 34 | file: '_bundles/ui-router-dsr' + extension, 35 | }, 36 | external: '@uirouter/core', 37 | plugins: plugins, 38 | }; 39 | -------------------------------------------------------------------------------- /src/DSRDataStore.ts: -------------------------------------------------------------------------------- 1 | import { StateOrName, UIRouter } from '@uirouter/core'; 2 | import { RecordedDSR } from './interface'; 3 | 4 | export interface DSRDataStore { 5 | init(router: UIRouter): void; 6 | // Gets the remembered DSR target state for a given state and params 7 | get(state: StateOrName): RecordedDSR[]; 8 | // Sets the remembered DSR target state for a given state and params 9 | set(state: StateOrName, recordedDSR: RecordedDSR[] | undefined): void; 10 | } 11 | 12 | export class StateObjectDataStore implements DSRDataStore { 13 | private router: UIRouter; 14 | 15 | private getState(stateOrName: StateOrName) { 16 | const state = this.router.stateService.get(stateOrName); 17 | return state && state.$$state(); 18 | } 19 | 20 | public init(router: UIRouter): void { 21 | this.router = router; 22 | } 23 | 24 | public get(stateOrName: StateOrName): RecordedDSR[] { 25 | return this.getState(stateOrName).$dsr || []; 26 | } 27 | 28 | public set(stateOrName: StateOrName, recordedDsr: RecordedDSR[]): void { 29 | const state = this.getState(stateOrName); 30 | if (recordedDsr) { 31 | state.$dsr = recordedDsr; 32 | } else { 33 | delete state.$dsr; 34 | } 35 | } 36 | } 37 | 38 | export class LocalStorageDataStore implements DSRDataStore { 39 | private router: UIRouter; 40 | private key = 'uiRouterDeepStateRedirect'; 41 | private _storage: Storage = localStorage; 42 | 43 | constructor(storage?: Storage) { 44 | this._storage = storage || localStorage; 45 | } 46 | 47 | private getStore() { 48 | const item = this._storage.getItem(this.key); 49 | return JSON.parse(item || '{}'); 50 | } 51 | 52 | private setStore(contents: any) { 53 | if (contents) { 54 | try { 55 | this._storage.setItem(this.key, JSON.stringify(contents)); 56 | } catch (err) { 57 | console.error( 58 | 'UI-Router Deep State Redirect: cannot store object in LocalStorage. Is there a circular reference?', 59 | contents 60 | ); 61 | console.error(err); 62 | } 63 | } else { 64 | this._storage.removeItem(this.key); 65 | } 66 | } 67 | 68 | private getStateName(stateOrName: StateOrName) { 69 | const state = this.router.stateService.get(stateOrName); 70 | return state && state.name; 71 | } 72 | 73 | public init(router: UIRouter): void { 74 | this.router = router; 75 | } 76 | 77 | public get(stateOrName: StateOrName): RecordedDSR[] { 78 | const stateName = this.getStateName(stateOrName); 79 | const store = this.getStore(); 80 | return store[stateName] || []; 81 | } 82 | 83 | public set(stateOrName: StateOrName, recordedDsr: RecordedDSR[]): void { 84 | const stateName = this.getStateName(stateOrName); 85 | const store = this.getStore(); 86 | store[stateName] = recordedDsr; 87 | this.setStore(store); 88 | } 89 | } 90 | 91 | export class SessionStorageDataStore extends LocalStorageDataStore { 92 | constructor() { 93 | super(sessionStorage); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/dsr.ts: -------------------------------------------------------------------------------- 1 | import { 2 | StateObject, 3 | StateDeclaration, 4 | Param, 5 | UIRouter, 6 | RawParams, 7 | StateOrName, 8 | TargetState, 9 | Transition, 10 | UIRouterPlugin, 11 | TransitionService, 12 | StateService, 13 | } from '@uirouter/core'; 14 | 15 | import { DSRDataStore, StateObjectDataStore } from './DSRDataStore'; 16 | import { _DSRConfig, DSRConfigObj, DSRFunction, DSRProp, ParamPredicate, RecordedDSR } from './interface'; 17 | 18 | class DSRPlugin implements UIRouterPlugin { 19 | name = 'deep-state-redirect'; 20 | 21 | dataStore: DSRDataStore; 22 | $transitions: TransitionService; 23 | $state: StateService; 24 | hookDeregFns = []; 25 | 26 | constructor($uiRouter: UIRouter, options: { dataStore: DSRDataStore }) { 27 | this.$transitions = $uiRouter.transitionService; 28 | this.$state = $uiRouter.stateService; 29 | this.dataStore = (options && options.dataStore) || new StateObjectDataStore(); 30 | this.dataStore.init($uiRouter); 31 | 32 | this.hookDeregFns.push( 33 | this.$transitions.onRetain( 34 | { retained: (state) => !!this.getDsrProp(state.self) }, 35 | this.recordDeepState.bind(this) 36 | ) 37 | ); 38 | this.hookDeregFns.push( 39 | this.$transitions.onEnter({ entering: (state) => !!this.getDsrProp(state.self) }, this.recordDeepState.bind(this)) 40 | ); 41 | this.hookDeregFns.push( 42 | this.$transitions.onBefore({ to: (state) => !!this.getDsrProp(state.self) }, this.deepStateRedirect.bind(this)) 43 | ); 44 | } 45 | 46 | dispose(_router: UIRouter): void { 47 | this.hookDeregFns.forEach((fn) => fn()); 48 | } 49 | 50 | /** 51 | * Resets deep state redirect 52 | * 53 | * A deep state is recorded for each DSR state. 54 | * This function resets recorded deep state redirect(s) to the initial value. 55 | * 56 | * If called with no parameters, the redirects for all states are reset. 57 | * 58 | * If called with a `state` parameter, the redirect for that state is reset. 59 | * 60 | * If called with `state` and `params` parameters, the redirect for that state and set of parameter values is reset. 61 | * 62 | * @param state (optional) the redirect for this state will be reset 63 | * @param params (optional) the redirect for the state and parameters will be reset 64 | */ 65 | reset(state?: StateOrName, params?: RawParams): void { 66 | const { $state } = this; 67 | if (!state) { 68 | $state.get().forEach((_state) => this.dataStore.set(_state, undefined)); 69 | } else if (!params) { 70 | this.dataStore.set(state, undefined); 71 | } else { 72 | const currentDSRS = this.dataStore.get(state); 73 | const $$state = $state.get(state).$$state(); 74 | this.dataStore.set(state, currentDSRS.filter(this.paramsEqual($$state, params, undefined, true))); 75 | } 76 | } 77 | 78 | /** 79 | * Returns the recorded redirect 80 | * 81 | * Returns the recorded redirect for a given DSR `state` (and optionally `params`). 82 | * 83 | * @param state the DSR state 84 | * @param params (optional) the parameter values 85 | * 86 | * @returns the recorded redirect `TargetState` 87 | */ 88 | getRedirect(state: StateOrName, params?: RawParams): TargetState { 89 | return this.getDeepStateRedirect(state, params); 90 | } 91 | 92 | private getDsrProp(state: StateDeclaration): DSRProp { 93 | return state.deepStateRedirect || state.dsr; 94 | } 95 | 96 | public getConfig(state: StateDeclaration): _DSRConfig { 97 | const { $state } = this; 98 | const dsrProp: DSRProp = this.getDsrProp(state); 99 | if (typeof dsrProp === 'undefined') return; 100 | 101 | let params: ParamPredicate; 102 | let defaultTarget: TargetState = typeof dsrProp === 'string' ? $state.target(dsrProp) : undefined; 103 | let fn: DSRFunction = typeof dsrProp === 'function' ? dsrProp : undefined; 104 | 105 | if (typeof dsrProp === 'object') { 106 | fn = dsrProp.fn; 107 | if (typeof dsrProp.default === 'object') { 108 | defaultTarget = $state.target(dsrProp.default.state, dsrProp.default.params, dsrProp.default.options); 109 | } else if (typeof dsrProp.default === 'string') { 110 | defaultTarget = $state.target(dsrProp.default); 111 | } 112 | 113 | const paramsProp = (dsrProp as DSRConfigObj).params; 114 | 115 | if (paramsProp === true) { 116 | params = () => true; 117 | } else if (Array.isArray(paramsProp)) { 118 | params = (param: Param) => paramsProp.indexOf(param.id) !== -1; 119 | } 120 | } 121 | 122 | fn = fn || (((transition: Transition, target: TargetState) => target) as DSRFunction); 123 | 124 | return { default: defaultTarget, params, fn }; 125 | } 126 | 127 | public paramsEqual( 128 | state: StateObject, 129 | transParams: RawParams, 130 | paramPredicate: ParamPredicate = () => true, 131 | negate = false 132 | ): (redirect: RecordedDSR) => boolean { 133 | const schema = state.parameters({ inherit: true }).filter(paramPredicate); 134 | 135 | return (redirect: RecordedDSR) => { 136 | const equals = Param.equals(schema, redirect.triggerParams, transParams); 137 | return negate ? !equals : equals; 138 | }; 139 | } 140 | 141 | private recordDeepState(transition: Transition, state: StateDeclaration): void { 142 | const { $state } = this; 143 | const hasParamsConfig = !!this.getConfig(state).params; 144 | const _state: StateObject = state.$$state(); 145 | 146 | transition.promise.then(() => { 147 | const transTo = transition.to(); 148 | const triggerParams = transition.params(); 149 | const target: TargetState = $state.target(transTo, triggerParams); 150 | const targetStateName = target.name(); 151 | const targetParams = target.params(); 152 | const recordedDSR: RecordedDSR = { triggerParams, targetStateName, targetParams }; 153 | 154 | if (hasParamsConfig) { 155 | const currentDSRS: RecordedDSR[] = this.dataStore.get(_state); 156 | const predicate = this.paramsEqual(transTo.$$state(), triggerParams, this.getConfig(state).params, true); 157 | const updatedDSRS = currentDSRS.filter(predicate).concat(recordedDSR); 158 | this.dataStore.set(_state, updatedDSRS); 159 | } else { 160 | this.dataStore.set(_state, [recordedDSR]); 161 | } 162 | }); 163 | } 164 | 165 | private deepStateRedirect(transition: Transition): TargetState | undefined { 166 | const opts = transition.options(); 167 | if (opts['ignoreDsr'] || (opts.custom && opts.custom.ignoreDsr)) return; 168 | 169 | const config: _DSRConfig = this.getConfig(transition.to()); 170 | let redirect: TargetState = this.getDeepStateRedirect(transition.to(), transition.params()); 171 | 172 | redirect = config.fn(transition, redirect); 173 | 174 | if (redirect && redirect.state() === transition.to()) return; 175 | 176 | return redirect; 177 | } 178 | 179 | private getTargetState(dsr: RecordedDSR): TargetState { 180 | return this.$state.target(dsr.targetStateName, dsr.targetParams); 181 | } 182 | 183 | private getDeepStateRedirect(stateOrName: StateOrName, params: RawParams): TargetState { 184 | const { $state } = this; 185 | const _state = $state.get(stateOrName); 186 | const state = _state && _state.$$state(); 187 | const config: _DSRConfig = this.getConfig(_state); 188 | const currentDSRS = this.dataStore.get(stateOrName); 189 | let recordedDSR: RecordedDSR; 190 | 191 | if (config.params) { 192 | const predicate = this.paramsEqual(state, params, config.params, false); 193 | const match = currentDSRS.find(predicate); 194 | recordedDSR = match && match; 195 | } else { 196 | recordedDSR = currentDSRS[0] && currentDSRS[0]; 197 | } 198 | 199 | let dsrTarget = recordedDSR ? this.getTargetState(recordedDSR) : config.default; 200 | 201 | if (dsrTarget) { 202 | // merge original params with deep state redirect params 203 | const targetParams = Object.assign({}, params, dsrTarget.params()); 204 | dsrTarget = $state.target(dsrTarget.state(), targetParams, dsrTarget.options()); 205 | } 206 | 207 | return dsrTarget; 208 | } 209 | } 210 | 211 | export { DSRPlugin }; 212 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './dsr'; 2 | -------------------------------------------------------------------------------- /src/interface.ts: -------------------------------------------------------------------------------- 1 | import { Param, RawParams, StateOrName, TargetState, Transition, TransitionOptions } from '@uirouter/core'; 2 | 3 | declare module '@uirouter/core/lib/state/interface' { 4 | interface StateDeclaration { 5 | dsr?: DSRProp; 6 | deepStateRedirect?: DSRProp; 7 | } 8 | } 9 | 10 | declare module '@uirouter/core/lib/state/stateObject' { 11 | interface StateObject { 12 | $dsr: RecordedDSR[]; 13 | } 14 | } 15 | 16 | export type ParamPredicate = (param: Param) => boolean; 17 | export type DSRProp = boolean | string | DSRFunction | DSRConfigObj; 18 | export type DSRFunction = (...args) => boolean | DSRTarget; 19 | export interface DSRTarget { 20 | state?: StateOrName; 21 | params?: RawParams; 22 | options?: TransitionOptions; 23 | } 24 | 25 | export interface DSRConfigObj { 26 | default?: string | DSRTarget; 27 | params?: boolean | string[]; 28 | fn?: DSRFunction; 29 | } 30 | 31 | export interface _DSRConfig { 32 | default?: TargetState; 33 | params?: ParamPredicate; 34 | fn?: (transition: Transition, something: any) => any; 35 | } 36 | 37 | export interface RecordedDSR { 38 | targetStateName: string; 39 | targetParams: RawParams; 40 | triggerParams: Record; 41 | } 42 | -------------------------------------------------------------------------------- /test/deepStateRedirectSpec.ts: -------------------------------------------------------------------------------- 1 | import { memoryLocationPlugin, servicesPlugin, StateDeclaration, StateService, UIRouter } from '@uirouter/core'; 2 | import { DSRPlugin } from '../src/dsr'; 3 | import { addCallbacks, getTestGoFn, pathFrom, resetTransitionLog } from './util'; 4 | 5 | // const equalityTester = (first, second) => 6 | // Object.keys(second).reduce((acc, key) => first[key] == second[key] && acc, true); 7 | // 8 | function getDSRStates(): StateDeclaration[] { 9 | // This function effectively returns the default DSR state at runtime 10 | function p7DSRFunction(transition, pendingRedirect) { 11 | // allow standard DSR behavior by returning pendingRedirect $dsr$.redirect has a state set 12 | if (pendingRedirect && pendingRedirect.state()) return pendingRedirect; 13 | 14 | // Otherwise, return a redirect object {state: "foo", params: {} } 15 | const redirectState = transition.params().param === '2' ? 'p7.child2' : 'p7.child1'; 16 | return transition.router.stateService.target(redirectState); 17 | } 18 | 19 | return [ 20 | { name: 'other' }, 21 | { name: 'tabs' }, 22 | { name: 'tabs.tabs1', deepStateRedirect: true }, 23 | { name: 'tabs.tabs1.deep' }, 24 | { name: 'tabs.tabs1.deep.nest' }, 25 | { name: 'tabs.tabs2', deepStateRedirect: true }, 26 | { name: 'tabs.tabs2.deep' }, 27 | { name: 'tabs.tabs2.deep.nest' }, 28 | { 29 | name: 'p1', 30 | url: '/p1/:param1/:param2', 31 | deepStateRedirect: { params: ['param1'] }, 32 | params: { param1: null, param2: null }, 33 | }, 34 | { name: 'p1.child' }, 35 | { name: 'p2', url: '/p2/:param1/:param2', deepStateRedirect: { params: true } }, 36 | { name: 'p2.child' }, 37 | { name: 'p3', url: '/p3/:param1', deepStateRedirect: { params: true } }, 38 | { name: 'p3.child' }, 39 | { name: 'p4', url: '/p4', dsr: { default: 'p4.child' } }, 40 | { name: 'p4.child' }, 41 | { name: 'p4.child2' }, 42 | { name: 'p5', url: '/p5', dsr: { default: { state: 'p5.child', params: { p5param: '1' } } } }, 43 | { name: 'p5.child', url: '/child/:p5param' }, 44 | { name: 'p6', url: '/p6/:param', dsr: { params: true, default: 'p6.child1' }, params: { param: null } }, 45 | { name: 'p6.child1' }, 46 | { name: 'p6.child2' }, 47 | { name: 'p6.child3' }, 48 | { name: 'p7', url: '/p7/:param', dsr: { default: {}, fn: p7DSRFunction }, params: { param: null } }, 49 | { name: 'p7.child1' }, 50 | { name: 'p7.child2' }, 51 | { name: 'p8', dsr: true }, 52 | { name: 'p8child1', parent: 'p8' }, 53 | { name: 'p8child2', parent: 'p8' }, 54 | ]; 55 | } 56 | 57 | function dsrReset(newStates) { 58 | addCallbacks(newStates); 59 | resetTransitionLog(); 60 | } 61 | 62 | let router: UIRouter = undefined; 63 | let $state: StateService = undefined; 64 | let $deepStateRedirect = undefined; 65 | let testGo = undefined; 66 | 67 | describe('deepStateRedirect', function () { 68 | beforeEach(async function (done) { 69 | router = new UIRouter(); 70 | router.plugin(servicesPlugin); 71 | router.plugin(memoryLocationPlugin); 72 | $deepStateRedirect = router.plugin(DSRPlugin); 73 | 74 | router.urlService.rules.otherwise('/'); 75 | $state = router.stateService; 76 | 77 | testGo = getTestGoFn(router); 78 | 79 | const newStates = getDSRStates(); 80 | dsrReset(newStates); 81 | newStates.forEach((state) => router.stateRegistry.register(state)); 82 | 83 | done(); 84 | }); 85 | 86 | describe(' - ', function () { 87 | it('should toggle between tab states', async function (done) { 88 | await testGo('tabs', { entered: 'tabs' }); 89 | await testGo('tabs.tabs2', { entered: 'tabs.tabs2' }); 90 | await testGo('tabs.tabs1', { entered: 'tabs.tabs1', exited: 'tabs.tabs2' }); 91 | 92 | done(); 93 | }); 94 | 95 | it('should redirect to tabs.tabs1.deep.nest', async function (done) { 96 | await testGo('tabs', { entered: 'tabs' }); 97 | await testGo('tabs.tabs2.deep.nest', { entered: ['tabs.tabs2', 'tabs.tabs2.deep', 'tabs.tabs2.deep.nest'] }); 98 | await testGo('tabs.tabs1', { 99 | entered: 'tabs.tabs1', 100 | exited: ['tabs.tabs2.deep.nest', 'tabs.tabs2.deep', 'tabs.tabs2'], 101 | }); 102 | await testGo( 103 | 'tabs.tabs2', 104 | { 105 | entered: ['tabs.tabs2', 'tabs.tabs2.deep', 'tabs.tabs2.deep.nest'], 106 | exited: 'tabs.tabs1', 107 | }, 108 | { redirect: 'tabs.tabs2.deep.nest' } 109 | ); 110 | 111 | done(); 112 | }); 113 | 114 | it('should forget a previous redirect to tabs.tabs2.deep.nest', async function (done) { 115 | await testGo('tabs', { entered: 'tabs' }); 116 | await testGo('tabs.tabs2.deep.nest', { entered: ['tabs.tabs2', 'tabs.tabs2.deep', 'tabs.tabs2.deep.nest'] }); 117 | await testGo('tabs.tabs1.deep.nest', { 118 | entered: ['tabs.tabs1', 'tabs.tabs1.deep', 'tabs.tabs1.deep.nest'], 119 | exited: ['tabs.tabs2.deep.nest', 'tabs.tabs2.deep', 'tabs.tabs2'], 120 | }); 121 | await testGo( 122 | 'tabs.tabs2', 123 | { 124 | entered: ['tabs.tabs2', 'tabs.tabs2.deep', 'tabs.tabs2.deep.nest'], 125 | exited: ['tabs.tabs1.deep.nest', 'tabs.tabs1.deep', 'tabs.tabs1'], 126 | }, 127 | { redirect: 'tabs.tabs2.deep.nest' } 128 | ); 129 | await testGo( 130 | 'tabs.tabs1', 131 | { 132 | entered: ['tabs.tabs1', 'tabs.tabs1.deep', 'tabs.tabs1.deep.nest'], 133 | exited: ['tabs.tabs2.deep.nest', 'tabs.tabs2.deep', 'tabs.tabs2'], 134 | }, 135 | { redirect: 'tabs.tabs1.deep.nest' } 136 | ); 137 | 138 | $deepStateRedirect.reset('tabs.tabs2'); 139 | 140 | await testGo('tabs.tabs2', { 141 | entered: ['tabs.tabs2'], 142 | exited: ['tabs.tabs1.deep.nest', 'tabs.tabs1.deep', 'tabs.tabs1'], 143 | }); 144 | await testGo( 145 | 'tabs.tabs1', 146 | { 147 | entered: ['tabs.tabs1', 'tabs.tabs1.deep', 'tabs.tabs1.deep.nest'], 148 | exited: ['tabs.tabs2'], 149 | }, 150 | { redirect: 'tabs.tabs1.deep.nest' } 151 | ); 152 | 153 | $deepStateRedirect.reset(); 154 | 155 | await testGo('tabs.tabs2', { 156 | entered: 'tabs.tabs2', 157 | exited: ['tabs.tabs1.deep.nest', 'tabs.tabs1.deep', 'tabs.tabs1'], 158 | }); 159 | await testGo('tabs.tabs1', { entered: 'tabs.tabs1', exited: ['tabs.tabs2'] }); 160 | 161 | done(); 162 | }); 163 | }); 164 | 165 | describe('with child substates configured using {parent: parentState}', function () { 166 | it('should remember and redirect to the last deepest state', async function (done) { 167 | await testGo('p8child1'); 168 | await testGo('other'); 169 | await testGo('p8', undefined, { redirect: 'p8child1' }); 170 | 171 | done(); 172 | }); 173 | }); 174 | 175 | describe('with configured params', function () { 176 | it('should redirect only when params match', async function (done) { 177 | await $state.go('p1', { param1: 'foo', param2: 'foo2' }); 178 | expect($state.current.name).toEqual('p1'); 179 | expect($state.params).toEqual({ '#': null, param1: 'foo', param2: 'foo2' } as any); 180 | 181 | await $state.go('.child'); 182 | expect($state.current.name).toEqual('p1.child'); 183 | 184 | await $state.go('p1', { param1: 'bar' }); 185 | expect($state.current.name).toEqual('p1'); 186 | 187 | await $state.go('p1', { param1: 'foo', param2: 'somethingelse' }); 188 | expect($state.current.name).toEqual('p1.child'); // DSR 189 | 190 | done(); 191 | }); 192 | 193 | // Test for issue #184 getRedirect() 194 | it('should be returned from getRedirect() for matching DSR params', async function (done) { 195 | await $state.go('p1', { param1: 'foo', param2: 'foo2' }); 196 | await $state.go('.child'); 197 | 198 | expect($deepStateRedirect.getRedirect('p1', { param1: 'foo' }).state().name).toBe('p1.child'); 199 | expect($deepStateRedirect.getRedirect('p1', { param1: 'bar' })).toBeUndefined(); 200 | 201 | done(); 202 | }); 203 | 204 | // Test for PR #165 205 | it('should consider only the params from the dsr configuration', async function (done) { 206 | router.stateRegistry.register({ 207 | name: 'rootState1', 208 | url: '/rootstate1/:rootstate1param', 209 | deepStateRedirect: { 210 | params: ['rootstate1param'], 211 | }, 212 | }); 213 | router.stateRegistry.register({ name: 'rootState2', url: '/rootstate2/:rootstate2param' }); 214 | router.stateRegistry.register({ name: 'rootState1.sub1', url: '/sub1' }); 215 | router.stateRegistry.register({ name: 'rootState1.sub2', url: '/sub2/:sub2param' }); 216 | 217 | await $state.go('rootState1.sub1', { rootstate1param: 'rootstate1param' }); 218 | await $state.go('rootState1.sub2', { rootstate1param: 'rootstate1param', sub2param: 'sub2param' }); 219 | await $state.go('rootState2', { rootstate2param: 'rootstate2param' }); 220 | await $state.go('rootState1', { rootstate1param: 'rootstate1param' }); 221 | 222 | const targetState = $deepStateRedirect.getRedirect('rootState1', { rootstate1param: 'rootstate1param' }); 223 | expect(targetState.state().name).toBe('rootState1.sub2'); 224 | 225 | done(); 226 | }); 227 | 228 | it('should not redirect if a param is resetted', async function (done) { 229 | await $state.go('p3', { param1: 'foo' }); 230 | await $state.go('.child'); 231 | await $state.go('p3', { param1: 'bar' }); 232 | await $state.go('.child'); 233 | 234 | $deepStateRedirect.reset('p3', { param1: 'foo' }); 235 | 236 | await $state.go('p3', { param1: 'foo' }); 237 | expect($state.current.name).toEqual('p3'); // DSR 238 | 239 | await $state.go('p3', { param1: 'bar' }); 240 | expect($state.current.name).toEqual('p3.child'); // DSR 241 | 242 | done(); 243 | }); 244 | 245 | it("should redirect only when all params match if 'params: true'", async function (done) { 246 | await $state.go('p2', { param1: 'foo', param2: 'foo2' }); 247 | 248 | expect($state.current.name).toEqual('p2'); 249 | expect($state.params).toEqual({ param1: 'foo', param2: 'foo2', '#': null } as any); 250 | 251 | await $state.go('.child'); 252 | expect($state.current.name).toEqual('p2.child'); 253 | 254 | await $state.go('p2', { param1: 'bar' }); 255 | expect($state.current.name).toEqual('p2'); 256 | 257 | await $state.go('p2', { param1: 'foo', param2: 'somethingelse' }); 258 | expect($state.current.name).toEqual('p2'); 259 | 260 | await $state.go('p2', { param1: 'foo', param2: 'foo2' }); 261 | expect($state.current.name).toEqual('p2.child'); // DSR 262 | 263 | done(); 264 | }); 265 | }); 266 | 267 | describe('ignoreDsr option', function () { 268 | it('should not redirect to tabs.tabs2.deep.nest when options are: { ignoreDsr: true }', async function (done) { 269 | await testGo('tabs', { entered: 'tabs' }); 270 | await testGo('tabs.tabs2.deep.nest', { entered: pathFrom('tabs.tabs2', 'tabs.tabs2.deep.nest') }); 271 | await testGo('tabs.tabs1.deep.nest', { 272 | entered: pathFrom('tabs.tabs1', 'tabs.tabs1.deep.nest'), 273 | exited: pathFrom('tabs.tabs2.deep.nest', 'tabs.tabs2'), 274 | }); 275 | await $state.go('tabs.tabs2', {}, { custom: { ignoreDsr: true } }); 276 | 277 | expect($state.current.name).toBe('tabs.tabs2'); 278 | 279 | done(); 280 | }); 281 | 282 | it('should redirect to tabs.tabs2.deep.nest after a previous ignoreDsr transition', async function (done) { 283 | await testGo('tabs', { entered: 'tabs' }); 284 | await testGo('tabs.tabs2.deep.nest', { entered: pathFrom('tabs.tabs2', 'tabs.tabs2.deep.nest') }); 285 | await testGo('tabs.tabs1.deep.nest', { 286 | entered: pathFrom('tabs.tabs1', 'tabs.tabs1.deep.nest'), 287 | exited: pathFrom('tabs.tabs2.deep.nest', 'tabs.tabs2'), 288 | }); 289 | 290 | await $state.go('tabs.tabs2', {}, { custom: { ignoreDsr: true } }); 291 | 292 | expect($state.current.name).toBe('tabs.tabs2'); 293 | 294 | resetTransitionLog(); 295 | await testGo( 296 | 'tabs.tabs1', 297 | { 298 | exited: 'tabs.tabs2', 299 | entered: pathFrom('tabs.tabs1', 'tabs.tabs1.deep.nest'), 300 | }, 301 | { redirect: 'tabs.tabs1.deep.nest' } 302 | ); 303 | 304 | done(); 305 | }); 306 | 307 | it('should remember the DSR state itself when transitioned to using ignoreDsr ', async function (done) { 308 | await testGo('tabs.tabs1.deep', { entered: pathFrom('tabs', 'tabs.tabs1.deep') }); 309 | await testGo('tabs.tabs2', { entered: 'tabs.tabs2', exited: pathFrom('tabs.tabs1.deep', 'tabs.tabs1') }); 310 | 311 | await $state.go('tabs.tabs1', {}, { custom: { ignoreDsr: true } }); 312 | 313 | expect($state.current.name).toBe('tabs.tabs1'); 314 | await $state.go('tabs.tabs2', {}, {}); 315 | 316 | expect($state.current.name).toBe('tabs.tabs2'); 317 | await $state.go('tabs.tabs1', {}, {}); 318 | 319 | expect($state.current.name).toBe('tabs.tabs1'); 320 | 321 | done(); 322 | }); 323 | }); 324 | 325 | describe('default substates', function () { 326 | // Test for issue #184 getRedirect() 327 | it('should be returned by getRedirect', function () { 328 | expect($deepStateRedirect.getRedirect('p4').state().name).toBe('p4.child'); 329 | }); 330 | 331 | it('should affect the first transition to the DSR state', async function (done) { 332 | await testGo('p4', undefined, { redirect: 'p4.child' }); 333 | await testGo('p4.child2'); 334 | await testGo('p4', undefined, { redirect: 'p4.child2' }); 335 | 336 | done(); 337 | }); 338 | 339 | it('should provide default parameters', async function (done) { 340 | await testGo('p5', undefined, { redirect: 'p5.child' }); 341 | expect($state.params).toEqual({ p5param: '1', '#': null } as any); 342 | 343 | done(); 344 | }); 345 | 346 | it('should redirect to the default state when params: true and transition to DSR with un-seen param values', async function (done) { 347 | await testGo('p6', undefined, { params: { param: '1' }, redirect: 'p6.child1' }); 348 | await testGo('p6.child2'); 349 | await testGo('p6', undefined, { params: { param: '1' }, redirect: 'p6.child2' }); 350 | // await testGo("p6", undefined, { params: { param: "2" }, redirect: 'p6.child1' }); 351 | 352 | done(); 353 | }); 354 | 355 | describe('in conjunction with a dsr fn', function () { 356 | it('should still invoke the dsr fn and use the result', async function (done) { 357 | // This effectively allows a function to determine DSR default 358 | await testGo('p7', undefined, { params: { param: '2' }, redirect: 'p7.child2' }); 359 | await testGo('p7.child1'); 360 | await testGo('p7', undefined, { params: { param: '2' }, redirect: 'p7.child1' }); 361 | 362 | done(); 363 | }); 364 | 365 | it('should still invoke the dsr fn and use the result', async function (done) { 366 | // This effectively allows the default DSR to be determined by a fn 367 | await testGo('p7', undefined, { redirect: 'p7.child1' }); 368 | await testGo('p1'); 369 | await testGo('p7', undefined, { params: { param: '2' }, redirect: 'p7.child1' }); 370 | 371 | done(); 372 | }); 373 | }); 374 | }); 375 | }); 376 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | // require all source files ending in "Spec" from the 2 | // current directory and all subdirectories 3 | 4 | require('@uirouter/core'); 5 | require('@uirouter/core/lib/vanilla'); 6 | require('../src/dsr'); 7 | 8 | var testsContext = require.context('.', true, /Spec$/); 9 | testsContext.keys().forEach(testsContext); 10 | -------------------------------------------------------------------------------- /test/util.ts: -------------------------------------------------------------------------------- 1 | var tLog, tExpected; 2 | import * as _ from 'lodash'; 3 | 4 | var TransitionAudit = function() { 5 | this.entered = []; 6 | this.exited = []; 7 | this.reactivated = []; 8 | this.inactivated = []; 9 | this.views = []; 10 | 11 | // this.toString = angular.bind(this, 12 | // function toString() { 13 | // var copy = {}; 14 | // angular.forEach(this, function(value, key) { 15 | // if (key === 'inactivated' || key === 'reactivated' || 16 | // key === 'entered' || key === 'exited') { 17 | // copy[key] = value; 18 | // } 19 | // }); 20 | // return angular.toJson(copy); 21 | // } 22 | // ); 23 | }; 24 | 25 | // Add callbacks to each 26 | export function addCallbacks(basicStates) { 27 | basicStates.forEach(function(state) { 28 | function deregisterView(state, cause) { 29 | var views = _.keys(state.$$state().views); 30 | tLog.views = _.difference(tLog.views, views); 31 | // console.log(cause + ":Deregistered Inactive view " + views + " for state " + state.name + ": ", tLog.views); 32 | } 33 | function registerView(state, cause) { 34 | var views = _.keys(state.$$state().views); 35 | tLog.views = _.union(tLog.views, views); 36 | // console.log(cause + ": Registered Inactive view " + views + " for state " + state.name + ": ", tLog.views); 37 | } 38 | 39 | state.onInactivate = function() { 40 | tLog.inactivated.push(state.name); 41 | registerView(state, 'Inactivate'); 42 | }; 43 | state.onReactivate = function() { 44 | tLog.reactivated.push(state.name); 45 | deregisterView(state, 'Reactivate'); 46 | }; 47 | state.onEnter = function() { 48 | tLog.entered.push(state.name); 49 | deregisterView(state, 'Enter '); 50 | }; 51 | state.onExit = function() { 52 | tLog.exited.push(state.name); 53 | deregisterView(state, 'Exit '); 54 | }; 55 | }); 56 | } 57 | 58 | export function pathFrom(start, end) { 59 | var startNodes = start.split('.'); 60 | var endNodes = end.split('.'); 61 | var reverse = startNodes.length > endNodes.length; 62 | if (reverse) { 63 | var tmp = startNodes; 64 | startNodes = endNodes; 65 | endNodes = tmp; 66 | } 67 | 68 | var common = _.intersection(endNodes, startNodes); 69 | var difference = _.difference(endNodes, startNodes); 70 | difference.splice(0, 0, common.pop()); 71 | 72 | var name = common.join('.'); 73 | var path = _.map(difference, function(segment) { 74 | name = (name ? name + '.' : '') + segment; 75 | return name; 76 | }); 77 | if (reverse) path.reverse(); 78 | return path; 79 | } 80 | 81 | export function getTestGoFn($uiRouter) { 82 | var $state = $uiRouter.stateService; 83 | 84 | /** 85 | * This test function does the following: 86 | * - Go to a state `state`. 87 | * - Flush transition 88 | * - Expect the current state to be the target state, or the expected redirect state 89 | * - analyse the transition log and expect 90 | * - The entered states to match tAdditional.entered 91 | * - The exited states to match tAdditional.exited 92 | * - The inactivated states to match tAdditional.inactivated 93 | * - The reactivated states to match tAdditional.reactivated 94 | * - Expect the active+inactive states to match the active+inactive views 95 | * 96 | * @param state: The target state 97 | * @param tAdditional: An object with the expected transitions 98 | * { 99 | * entered: statename or [ statenamearray ], 100 | * exited: statename or [ statenamearray ], 101 | * inactivated: statename or [ statenamearray ], 102 | * reactivated: statename or [ statenamearray ] 103 | * } 104 | * note: statenamearray may be built using the pathFrom helper function 105 | * @param options: options which modify the expected transition behavior 106 | * { redirect: redirectstatename } 107 | */ 108 | async function testGo(state, tAdditional, options) { 109 | await $state.go(state, options && options.params, options); 110 | 111 | var expectRedirect = options && options.redirect; 112 | if (!expectRedirect) expect($state.current.name).toBe(state); 113 | else expect($state.current.name).toBe(expectRedirect); 114 | 115 | // var root = $state.$current.path[0].parent; 116 | // var __inactives = root.parent; 117 | 118 | // If ct.ui.router.extras.sticky module is included, then root.parent holds the inactive states/views 119 | // if (__inactives) { 120 | // var __inactiveViews = _.keys(__inactives.locals); 121 | // var extra = _.difference(__inactiveViews, tLog.views); 122 | // var missing = _.difference(tLog.views, __inactiveViews); 123 | // 124 | // expect("Extra Views: " + extra).toEqual("Extra Views: " + []); 125 | // expect("Missing Views: " + missing).toEqual("Missing Views: " + []); 126 | // } 127 | 128 | if (tExpected && tAdditional) { 129 | // append all arrays in tAdditional to arrays in tExpected 130 | Object.keys(tAdditional).forEach(key => (tExpected[key] = tExpected[key].concat(tAdditional[key]))); 131 | // angular.forEach(tAdditional, function (value, key) { 132 | // tExpected[key] = tExpected[key].concat(tAdditional[key]); 133 | // }); 134 | 135 | Object.keys(tLog) 136 | .filter(x => x !== 'views') 137 | .forEach(key => { 138 | // angular.forEach(_.without(_.keys(tLog), 'views'), function(key) { 139 | var left = key + ': ' + JSON.stringify(tLog[key]); 140 | var right = key + ': ' + JSON.stringify(tExpected[key]); 141 | expect(left).toBe(right); 142 | }); 143 | } 144 | 145 | return Promise.resolve(); 146 | } 147 | 148 | return testGo; 149 | } 150 | 151 | export function resetTransitionLog() { 152 | tLog = new TransitionAudit(); 153 | tExpected = new TransitionAudit(); 154 | } 155 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "emitDecoratorMetadata": true, 4 | "experimentalDecorators": true, 5 | "moduleResolution": "node", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "lib": ["es6", "dom"], 9 | "allowSyntheticDefaultImports": true, 10 | "outDir": "lib", 11 | "declaration": true, 12 | "sourceMap": true 13 | }, 14 | "files": ["src/index.ts"] 15 | } 16 | --------------------------------------------------------------------------------