mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-17 10:41:13 +08:00
chore(): migrate vue to typescript (#15928)
This commit is contained in:

committed by
Mike Hartington

parent
d800c48734
commit
e251ca71b4
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": ["env"]
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
env: {
|
|
||||||
browser: true,
|
|
||||||
node: true,
|
|
||||||
es6: true,
|
|
||||||
},
|
|
||||||
extends: [
|
|
||||||
'prettier',
|
|
||||||
'eslint:recommended',
|
|
||||||
'plugin:vue/recommended',
|
|
||||||
'plugin:jest/recommended',
|
|
||||||
'plugin:promise/recommended',
|
|
||||||
],
|
|
||||||
plugins: ['prettier', 'promise', 'jest'],
|
|
||||||
parserOptions: {
|
|
||||||
sourceType: 'module',
|
|
||||||
ecmaVersion: 2017,
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
'no-console': 0,
|
|
||||||
'prettier/prettier': 'error',
|
|
||||||
'linebreak-style': ['error', 'unix'],
|
|
||||||
'promise/no-callback-in-promise': 0,
|
|
||||||
indent: ['error', 2],
|
|
||||||
semi: ['error', 'never'],
|
|
||||||
quotes: ['error', 'single'],
|
|
||||||
},
|
|
||||||
}
|
|
2
vue/.gitignore
vendored
2
vue/.gitignore
vendored
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
dist/
|
dist/
|
||||||
node_modules/
|
node_modules/
|
||||||
|
src/**/*.js
|
||||||
|
types/**/*.map
|
||||||
|
|
||||||
# ignore log files
|
# ignore log files
|
||||||
*.log
|
*.log
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"printWidth": 100,
|
|
||||||
"singleQuote": true,
|
|
||||||
"semi": false,
|
|
||||||
"trailingComma": "es5"
|
|
||||||
}
|
|
@ -10,6 +10,8 @@
|
|||||||
<script>window.disableIonicTransitions = true</script>
|
<script>window.disableIonicTransitions = true</script>
|
||||||
<script src="https://unpkg.com/vue"></script>
|
<script src="https://unpkg.com/vue"></script>
|
||||||
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-property-decorator@latest/lib/vue-property-decorator.umd.js"></script>
|
||||||
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
||||||
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
<meta name="msapplication-tap-highlight" content="no">
|
<meta name="msapplication-tap-highlight" content="no">
|
||||||
<script src="https://unpkg.com/vue"></script>
|
<script src="https://unpkg.com/vue"></script>
|
||||||
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-property-decorator@latest/lib/vue-property-decorator.umd.js"></script>
|
||||||
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
||||||
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
<meta name="msapplication-tap-highlight" content="no">
|
<meta name="msapplication-tap-highlight" content="no">
|
||||||
<script src="https://unpkg.com/vue"></script>
|
<script src="https://unpkg.com/vue"></script>
|
||||||
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-property-decorator@latest/lib/vue-property-decorator.umd.js"></script>
|
||||||
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
||||||
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
<meta name="msapplication-tap-highlight" content="no">
|
<meta name="msapplication-tap-highlight" content="no">
|
||||||
<script src="https://unpkg.com/vue"></script>
|
<script src="https://unpkg.com/vue"></script>
|
||||||
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-property-decorator@latest/lib/vue-property-decorator.umd.js"></script>
|
||||||
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
||||||
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
<meta name="msapplication-tap-highlight" content="no">
|
<meta name="msapplication-tap-highlight" content="no">
|
||||||
<script src="https://unpkg.com/vue"></script>
|
<script src="https://unpkg.com/vue"></script>
|
||||||
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-property-decorator@latest/lib/vue-property-decorator.umd.js"></script>
|
||||||
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
||||||
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
<meta name="msapplication-tap-highlight" content="no">
|
<meta name="msapplication-tap-highlight" content="no">
|
||||||
<script src="https://unpkg.com/vue"></script>
|
<script src="https://unpkg.com/vue"></script>
|
||||||
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-property-decorator@latest/lib/vue-property-decorator.umd.js"></script>
|
||||||
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
||||||
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
||||||
|
82
vue/cookbook/tabs.html
Normal file
82
vue/cookbook/tabs.html
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Ionic v4 + Vue.js - Ionic tabs</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="format-detection" content="telephone=no">
|
||||||
|
<meta name="msapplication-tap-highlight" content="no">
|
||||||
|
<script src="https://unpkg.com/vue"></script>
|
||||||
|
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-class-component@latest/dist/vue-class-component.js"></script>
|
||||||
|
<script src="https://unpkg.com/vue-property-decorator@latest/lib/vue-property-decorator.umd.js"></script>
|
||||||
|
<script src="https://unpkg.com/@modus/ionic-vue@latest/dist/ionic-vue.js"></script>
|
||||||
|
<script src="https://unpkg.com/@ionic/core@latest/dist/ionic.js"></script>
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/@ionic/core@latest/css/ionic.bundle.css"/>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<ion-app>
|
||||||
|
<Home/>
|
||||||
|
</ion-app>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const Toolbar = Vue.component('Toolbar', {
|
||||||
|
name: 'Toolbar',
|
||||||
|
props: { title: String, backURL: String },
|
||||||
|
template: `<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-back-button :default-href="backURL"/>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>{{ title }}</ion-title>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>`
|
||||||
|
})
|
||||||
|
|
||||||
|
const Home = Vue.component('Home', {
|
||||||
|
template: `<ion-page class="ion-page">
|
||||||
|
<toolbar title="Home"/>
|
||||||
|
<ion-content class="ion-content" padding>
|
||||||
|
<ion-tabs>
|
||||||
|
<ion-tab href="schedule" label="schedule" icon="calendar" name="schedule">
|
||||||
|
<ion-vue-router/>
|
||||||
|
</ion-tab>
|
||||||
|
<ion-tab href="speakers" label="speakers" icon="contacts" name="speakers">
|
||||||
|
<ion-vue-router name="speakers"/>
|
||||||
|
</ion-tab>
|
||||||
|
</ion-tabs>
|
||||||
|
</ion-content>
|
||||||
|
</ion-page>`
|
||||||
|
})
|
||||||
|
|
||||||
|
const Page = {
|
||||||
|
template: '<ion-button @click="goBack">Go back</ion-button>',
|
||||||
|
methods: {
|
||||||
|
goBack() {
|
||||||
|
this.$router.back()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Schedule = {
|
||||||
|
template: `<ion-button @click="$router.push('page')">To page</ion-button>`
|
||||||
|
}
|
||||||
|
|
||||||
|
const Speakers = {
|
||||||
|
template: '<h1>Speakers list</h1>'
|
||||||
|
}
|
||||||
|
|
||||||
|
Vue.config.ignoredElements.push(/^ion-/)
|
||||||
|
|
||||||
|
new Vue({
|
||||||
|
router: new IonicVue.IonicVueRouter({
|
||||||
|
routes: [
|
||||||
|
{ path: '/', components: {default: Schedule, speakers: Speakers} },
|
||||||
|
{ path: '/page', component: Page }
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
}).$mount('ion-app')
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,12 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
testURL: 'http://localhost/',
|
|
||||||
moduleFileExtensions: ['js', 'vue'],
|
|
||||||
moduleNameMapper: {
|
|
||||||
'^vue$': 'vue/dist/vue.common.js',
|
|
||||||
},
|
|
||||||
transform: {
|
|
||||||
'^.+\\.js$': '<rootDir>/node_modules/babel-jest',
|
|
||||||
'.*\\.(vue)$': '<rootDir>/node_modules/jest-vue-preprocessor',
|
|
||||||
},
|
|
||||||
"testResultsProcessor": "jest-sonar-reporter"
|
|
||||||
}
|
|
6949
vue/package-lock.json
generated
6949
vue/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -7,6 +7,7 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "github:ionic-team/ionic",
|
"repository": "github:ionic-team/ionic",
|
||||||
"main": "dist/ionic-vue.common.js",
|
"main": "dist/ionic-vue.common.js",
|
||||||
|
"typings": "types/index.d.ts",
|
||||||
"module": "dist/ionic-vue.esm.js",
|
"module": "dist/ionic-vue.esm.js",
|
||||||
"unpkg": "dist/ionic-vue.js",
|
"unpkg": "dist/ionic-vue.js",
|
||||||
"jsdelivr": "dist/ionic-vue.js",
|
"jsdelivr": "dist/ionic-vue.js",
|
||||||
@ -15,7 +16,9 @@
|
|||||||
],
|
],
|
||||||
"files": [
|
"files": [
|
||||||
"src/",
|
"src/",
|
||||||
"dist/*.js"
|
"types/",
|
||||||
|
"dist/*.js",
|
||||||
|
"dist/*.ts"
|
||||||
],
|
],
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/ionic-team/ionic/issues"
|
"url": "https://github.com/ionic-team/ionic/issues"
|
||||||
@ -25,6 +28,7 @@
|
|||||||
"ion",
|
"ion",
|
||||||
"vuejs",
|
"vuejs",
|
||||||
"vue",
|
"vue",
|
||||||
|
"typescript",
|
||||||
"router",
|
"router",
|
||||||
"routing",
|
"routing",
|
||||||
"plugin",
|
"plugin",
|
||||||
@ -42,27 +46,21 @@
|
|||||||
"watch": "rollup -c -w",
|
"watch": "rollup -c -w",
|
||||||
"build": "NODE_ENV=production rollup -c --configProd",
|
"build": "NODE_ENV=production rollup -c --configProd",
|
||||||
"clean": "node scripts/clean.js",
|
"clean": "node scripts/clean.js",
|
||||||
"lint": "eslint src/**/* test/**/*",
|
"lint": "tslint --project .",
|
||||||
|
"lint.fix": "tslint --project . --fix",
|
||||||
"test": "jest --coverage --verbose"
|
"test": "jest --coverage --verbose"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-jest": "^23.4.2",
|
|
||||||
"babel-preset-env": "^1.7.0",
|
|
||||||
"buble": "^0.19.3",
|
|
||||||
"eslint": "^5.1.0",
|
|
||||||
"eslint-config-prettier": "^2.9.0",
|
|
||||||
"eslint-plugin-jest": "^21.18.0",
|
|
||||||
"eslint-plugin-prettier": "^2.6.2",
|
|
||||||
"eslint-plugin-promise": "^3.8.0",
|
|
||||||
"eslint-plugin-vue": "^4.5.0",
|
|
||||||
"fs-extra": "^7.0.0",
|
|
||||||
"jest": "^23.4.2",
|
|
||||||
"jest-sonar-reporter": "^2.0.0",
|
|
||||||
"jest-vue-preprocessor": "^1.4.0",
|
|
||||||
"rollup": "^0.62.0",
|
"rollup": "^0.62.0",
|
||||||
"rollup-plugin-buble": "^0.19.2",
|
|
||||||
"rollup-plugin-terser": "^1.0.1",
|
"rollup-plugin-terser": "^1.0.1",
|
||||||
"rollup-plugin-vue": "^4.3.0"
|
"rollup-plugin-vue": "^4.3.0",
|
||||||
|
"rollup-plugin-typescript2": "^0.17.1",
|
||||||
|
"tslib": "1.9.3",
|
||||||
|
"tslint": "5.11.0",
|
||||||
|
"tslint-ionic-rules": "0.0.19",
|
||||||
|
"typescript": "3.1.1",
|
||||||
|
"vue-class-component": "^6.2.0",
|
||||||
|
"vue-property-decorator": "^7.2.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vue": "^2.5.17",
|
"vue": "^2.5.17",
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import buble from 'rollup-plugin-buble'
|
|
||||||
import vue from 'rollup-plugin-vue'
|
import vue from 'rollup-plugin-vue'
|
||||||
import { terser } from 'rollup-plugin-terser'
|
import { terser } from 'rollup-plugin-terser'
|
||||||
|
import typescript from 'rollup-plugin-typescript2'
|
||||||
import { version as packageVersion } from './package.json'
|
import { version as packageVersion } from './package.json'
|
||||||
|
|
||||||
const version = process.env.VERSION || packageVersion
|
const version = process.env.VERSION || packageVersion
|
||||||
|
|
||||||
const banner = `
|
const banner = `/*!
|
||||||
/*!
|
|
||||||
* @ionic/vue v${version}
|
* @ionic/vue v${version}
|
||||||
* ${new Date().getFullYear()} Modus Create
|
* ${new Date().getFullYear()} Modus Create
|
||||||
* @license MIT
|
* @license MIT
|
||||||
@ -31,28 +30,29 @@ function outputConfig(suffix, format, opts = {}) {
|
|||||||
|
|
||||||
function baseConfig() {
|
function baseConfig() {
|
||||||
return {
|
return {
|
||||||
input: resolve('./src/index.js'),
|
input: resolve('./src/index.ts'),
|
||||||
output: [
|
output: [
|
||||||
outputConfig('', 'umd', { globals: {} }),
|
outputConfig('', 'umd', {
|
||||||
|
globals: {
|
||||||
|
vue: 'Vue',
|
||||||
|
'vue-class-component': 'VueClassComponent',
|
||||||
|
'vue-property-decorator': 'vue-property-decorator',
|
||||||
|
},
|
||||||
|
}),
|
||||||
outputConfig('.esm', 'esm'),
|
outputConfig('.esm', 'esm'),
|
||||||
outputConfig('.common', 'cjs'),
|
outputConfig('.common', 'cjs'),
|
||||||
],
|
],
|
||||||
external: [
|
external: [
|
||||||
'vue',
|
'vue',
|
||||||
'vue-router',
|
'vue-router',
|
||||||
|
'vue-class-component',
|
||||||
|
'vue-property-decorator',
|
||||||
'@ionic/core/loader',
|
'@ionic/core/loader',
|
||||||
'@ionic/core/css/ionic.bundle.css',
|
'@ionic/core/css/ionic.bundle.css',
|
||||||
'@ionic/core/dist/ionic/svg',
|
'@ionic/core/dist/ionic/svg',
|
||||||
'ionicons/dist/collection/icon/icon.css',
|
'ionicons/dist/collection/icon/icon.css',
|
||||||
],
|
],
|
||||||
plugins: [
|
plugins: [vue(), typescript({ useTsconfigDeclarationDir: true })],
|
||||||
vue(),
|
|
||||||
buble({
|
|
||||||
transforms: {
|
|
||||||
dangerousForOf: true,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
// A proxy method that initializes the controller and calls requested method
|
|
||||||
export function proxyMethod(tag, method, ...opts) {
|
|
||||||
return initController(tag).then(ctrl => ctrl[method].apply(ctrl, opts))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize an Ionic controller and append it to DOM
|
|
||||||
export function initController(tag) {
|
|
||||||
let element = document.querySelector(tag)
|
|
||||||
|
|
||||||
if (element) {
|
|
||||||
return element.componentOnReady()
|
|
||||||
}
|
|
||||||
|
|
||||||
return document.body.appendChild(document.createElement(tag)).componentOnReady()
|
|
||||||
}
|
|
17
vue/src/api-utils.ts
Normal file
17
vue/src/api-utils.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { HTMLStencilElement } from './interfaces';
|
||||||
|
|
||||||
|
// A proxy method that initializes the controller and calls requested method
|
||||||
|
export function proxyMethod(tag: string, method: string, ...opts: any[]): Promise<any> {
|
||||||
|
return initController(tag).then((ctrl: any) => ctrl[method].apply(ctrl, opts));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize an Ionic controller and append it to DOM
|
||||||
|
export function initController(tag: string): Promise<HTMLStencilElement> {
|
||||||
|
let element = document.querySelector(tag) as HTMLElement;
|
||||||
|
|
||||||
|
if (!element) {
|
||||||
|
element = document.body.appendChild(document.createElement(tag));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (element as HTMLStencilElement).componentOnReady();
|
||||||
|
}
|
103
vue/src/api.js
103
vue/src/api.js
@ -1,103 +0,0 @@
|
|||||||
import Delegate from './framework-delegate'
|
|
||||||
import ProxyController from './proxy-controller'
|
|
||||||
import ProxyMenuController from './proxy-menu-controller'
|
|
||||||
import ProxyDelegateController from './proxy-delegate-controller'
|
|
||||||
|
|
||||||
let _Vue, _Delegate
|
|
||||||
|
|
||||||
export default class Api {
|
|
||||||
// Create or return a ActionSheetController instance
|
|
||||||
get actionSheetController() {
|
|
||||||
return getOrCreateController('ion-action-sheet-controller')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or return an AlertController instance
|
|
||||||
get alertController() {
|
|
||||||
return getOrCreateController('ion-alert-controller')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or return a LoadingController instance
|
|
||||||
get loadingController() {
|
|
||||||
return getOrCreateController('ion-loading-controller')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or return a MenuController instance
|
|
||||||
get menuController() {
|
|
||||||
return getOrCreateMenuController('ion-menu-controller')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or return a ModalController instance
|
|
||||||
get modalController() {
|
|
||||||
return getOrCreateDelegatedController('ion-modal-controller')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or return a PopoverController instance
|
|
||||||
get popoverController() {
|
|
||||||
return getOrCreateDelegatedController('ion-popover-controller')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create or return a ToastController instance
|
|
||||||
get toastController() {
|
|
||||||
return getOrCreateController('ion-toast-controller')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cached controllers
|
|
||||||
Api.cache = {
|
|
||||||
'ion-action-sheet-controller': null,
|
|
||||||
'ion-alert-controller': null,
|
|
||||||
'ion-loading-controller': null,
|
|
||||||
'ion-menu-controller': null,
|
|
||||||
'ion-modal-controller': null,
|
|
||||||
'ion-popover-controller': null,
|
|
||||||
'ion-toast-controller': null,
|
|
||||||
}
|
|
||||||
|
|
||||||
Api.install = function(Vue) {
|
|
||||||
// If installed - skip
|
|
||||||
if (Api.install.installed && _Vue === Vue) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_Vue = Vue
|
|
||||||
_Delegate = new Delegate(Vue)
|
|
||||||
|
|
||||||
Api.install.installed = true
|
|
||||||
|
|
||||||
// Ignore Ionic custom elements
|
|
||||||
Vue.config.ignoredElements.push(/^ion-/)
|
|
||||||
|
|
||||||
// Give access to the API methods
|
|
||||||
Object.defineProperty(Vue.prototype, '$ionic', {
|
|
||||||
get() {
|
|
||||||
return new Api()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get existing Base controller instance or initialize a new one
|
|
||||||
function getOrCreateController(tag) {
|
|
||||||
if (!Api.cache[tag]) {
|
|
||||||
Api.cache[tag] = new ProxyController(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Api.cache[tag]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get existing Menu controller instance or initialize a new one
|
|
||||||
function getOrCreateMenuController(tag) {
|
|
||||||
if (!Api.cache[tag]) {
|
|
||||||
Api.cache[tag] = new ProxyMenuController(tag)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Api.cache[tag]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get existing Delegated controller instance or initialize a new one
|
|
||||||
function getOrCreateDelegatedController(tag) {
|
|
||||||
if (!Api.cache[tag]) {
|
|
||||||
Api.cache[tag] = new ProxyDelegateController(tag, _Delegate)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Api.cache[tag]
|
|
||||||
}
|
|
109
vue/src/api.ts
Normal file
109
vue/src/api.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import Vue, { PluginFunction } from 'vue';
|
||||||
|
import { ApiCache, FrameworkDelegate } from './interfaces';
|
||||||
|
import Delegate from './framework-delegate';
|
||||||
|
import ProxyController from './proxy-controller';
|
||||||
|
import ProxyMenuController from './proxy-menu-controller';
|
||||||
|
import ProxyDelegateController from './proxy-delegate-controller';
|
||||||
|
|
||||||
|
let _Vue: typeof Vue, _Delegate: FrameworkDelegate;
|
||||||
|
|
||||||
|
export default class Api {
|
||||||
|
static cache: ApiCache;
|
||||||
|
static installed = false;
|
||||||
|
static install: PluginFunction<never>;
|
||||||
|
|
||||||
|
// Create or return a ActionSheetController instance
|
||||||
|
get actionSheetController(): ProxyController {
|
||||||
|
return getOrCreateController('ion-action-sheet-controller');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or return an AlertController instance
|
||||||
|
get alertController(): ProxyController {
|
||||||
|
return getOrCreateController('ion-alert-controller');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or return a LoadingController instance
|
||||||
|
get loadingController(): ProxyController {
|
||||||
|
return getOrCreateController('ion-loading-controller');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or return a MenuController instance
|
||||||
|
get menuController(): ProxyMenuController {
|
||||||
|
return getOrCreateMenuController('ion-menu-controller');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or return a ModalController instance
|
||||||
|
get modalController(): ProxyDelegateController {
|
||||||
|
return getOrCreateDelegatedController('ion-modal-controller');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or return a PopoverController instance
|
||||||
|
get popoverController(): ProxyDelegateController {
|
||||||
|
return getOrCreateDelegatedController('ion-popover-controller');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create or return a ToastController instance
|
||||||
|
get toastController(): ProxyController {
|
||||||
|
return getOrCreateController('ion-toast-controller');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cached controllers
|
||||||
|
Api.cache = {
|
||||||
|
'ion-action-sheet-controller': null,
|
||||||
|
'ion-alert-controller': null,
|
||||||
|
'ion-loading-controller': null,
|
||||||
|
'ion-menu-controller': null,
|
||||||
|
'ion-modal-controller': null,
|
||||||
|
'ion-popover-controller': null,
|
||||||
|
'ion-toast-controller': null,
|
||||||
|
};
|
||||||
|
|
||||||
|
Api.install = (Vue): void => {
|
||||||
|
// If installed - skip
|
||||||
|
if (Api.installed && _Vue === Vue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_Vue = Vue;
|
||||||
|
_Delegate = new Delegate(Vue);
|
||||||
|
|
||||||
|
Api.installed = true;
|
||||||
|
|
||||||
|
// Ignore Ionic custom elements
|
||||||
|
Vue.config.ignoredElements.push(/^ion-/);
|
||||||
|
|
||||||
|
// Give access to the API methods
|
||||||
|
Object.defineProperty(Vue.prototype, '$ionic', {
|
||||||
|
get() {
|
||||||
|
return new Api();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get existing Base controller instance or initialize a new one
|
||||||
|
function getOrCreateController(tag: string): ProxyController {
|
||||||
|
if (!Api.cache[tag]) {
|
||||||
|
Api.cache[tag] = new ProxyController(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Api.cache[tag];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get existing Menu controller instance or initialize a new one
|
||||||
|
function getOrCreateMenuController(tag: string): ProxyMenuController {
|
||||||
|
if (!Api.cache[tag]) {
|
||||||
|
Api.cache[tag] = new ProxyMenuController(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Api.cache[tag];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get existing Delegated controller instance or initialize a new one
|
||||||
|
function getOrCreateDelegatedController(tag: string): ProxyDelegateController {
|
||||||
|
if (!Api.cache[tag]) {
|
||||||
|
Api.cache[tag] = new ProxyDelegateController(tag, _Delegate);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Api.cache[tag];
|
||||||
|
}
|
@ -4,18 +4,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import catchIonicGoBack from '../mixins/catch-ionic-go-back.js'
|
import { Prop } from 'vue-property-decorator';
|
||||||
|
import Component, { mixins } from 'vue-class-component';
|
||||||
|
import CatchIonicGoBack from '../mixins/catch-ionic-go-back';
|
||||||
|
|
||||||
export default {
|
@Component
|
||||||
name: 'IonVueRouter',
|
export default class IonVueRouter extends mixins(CatchIonicGoBack) {
|
||||||
mixins: [catchIonicGoBack],
|
@Prop({ default: 'default'}) name!: string;
|
||||||
props: {
|
|
||||||
// A name to call "named views" by
|
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
default: 'default',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -23,123 +23,112 @@
|
|||||||
</ion-router-outlet>
|
</ion-router-outlet>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script lang="ts">
|
||||||
import catchIonicGoBack from '../mixins/catch-ionic-go-back.js'
|
import { Prop } from 'vue-property-decorator';
|
||||||
|
import Component, { mixins } from 'vue-class-component';
|
||||||
|
import CatchIonicGoBack from '../mixins/catch-ionic-go-back';
|
||||||
|
import { IonRouterOutlet } from '../interfaces';
|
||||||
|
|
||||||
export default {
|
@Component
|
||||||
name: 'IonVueRouter',
|
export default class IonVueRouter extends mixins(CatchIonicGoBack) {
|
||||||
mixins: [catchIonicGoBack],
|
@Prop({ default: 'default'}) name!: string;
|
||||||
props: {
|
@Prop({ default: false }) bindCSS!: boolean;
|
||||||
// A name to call "named views" by
|
@Prop({ default: true }) animated!: boolean;
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
default: 'default',
|
|
||||||
},
|
|
||||||
// Set CSS classes during transitions
|
|
||||||
bindCSS: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
// Animate transitions or not
|
|
||||||
animated: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
// Currently visible component
|
|
||||||
leavingEl: null,
|
|
||||||
|
|
||||||
// Component to be rendered
|
// Currently visible component
|
||||||
enteringEl: null,
|
leavingEl: HTMLElement;
|
||||||
|
// Component to be rendered
|
||||||
|
enteringEl: HTMLElement;
|
||||||
|
// Flag to see if we're still in a transition
|
||||||
|
inTransition = false;
|
||||||
|
customTransition = false;
|
||||||
|
|
||||||
// Flag to see if we're still in a transition
|
|
||||||
inTransition: false,
|
|
||||||
|
|
||||||
customTransition: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
created() {
|
||||||
// Cancel navigation if there's a running transition
|
// Cancel navigation if there's a running transition
|
||||||
this.$router.beforeEach((to, from, next) => {
|
this.$router.beforeEach((to, _from, next) => {
|
||||||
this.customTransition = to.meta.customTransition || false
|
this.customTransition = to.meta.customTransition || false
|
||||||
return this.$nextTick(() => {
|
return this.$nextTick(() => {
|
||||||
return next(!this.inTransition)
|
return next(!this.inTransition as false);
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
}
|
||||||
methods: {
|
|
||||||
transition(enteringEl, leavingEl) {
|
|
||||||
// Get the reference to the Ionic component handling the transitions
|
|
||||||
const ionRouterOutlet = this.$refs.ionRouterOutlet
|
|
||||||
|
|
||||||
// The Ionic framework didn't load - skip animations
|
transition(enteringEl: HTMLElement, leavingEl: HTMLElement) {
|
||||||
if (typeof ionRouterOutlet.componentOnReady === 'undefined') {
|
// Get the reference to the Ionic component handling the transitions
|
||||||
return
|
const ionRouterOutlet = this.$refs.ionRouterOutlet as IonRouterOutlet;
|
||||||
}
|
|
||||||
|
|
||||||
// Skip animations if there's no component to navigate to
|
// The Ionic framework didn't load - skip animations
|
||||||
// or the current and the "to-be-rendered" components are the same
|
if (typeof ionRouterOutlet.componentOnReady === 'undefined') {
|
||||||
if (!enteringEl || enteringEl === leavingEl) {
|
return;
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Add the proper Ionic classes, important for smooth transitions
|
// Skip animations if there's no component to navigate to
|
||||||
enteringEl.classList.add('ion-page', 'ion-page-invisible')
|
// or the current and the "to-be-rendered" components are the same
|
||||||
|
if (!enteringEl || enteringEl === leavingEl) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Commit to the transition as soon as the Ionic Router Outlet is ready
|
// Add the proper Ionic classes, important for smooth transitions
|
||||||
return ionRouterOutlet.componentOnReady().then(el => {
|
enteringEl.classList.add('ion-page', 'ion-page-invisible')
|
||||||
return el.commit(enteringEl, leavingEl, {
|
|
||||||
deepWait: true,
|
|
||||||
duration: this.getDuration(),
|
|
||||||
direction: this.getDirection(),
|
|
||||||
showGoBack: this.$router.canGoBack(),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// Instant transition if we don't want to animate
|
|
||||||
getDuration() {
|
|
||||||
return !this.animated ? 0 : undefined
|
|
||||||
},
|
|
||||||
// Get the navigation direction from the router
|
|
||||||
getDirection() {
|
|
||||||
return this.$router.direction === 1 ? 'forward' : 'back'
|
|
||||||
},
|
|
||||||
// Set the component to be rendered before we render the new route
|
|
||||||
beforeEnter(el) {
|
|
||||||
this.enteringEl = el
|
|
||||||
},
|
|
||||||
// Remember the current component before we leave the route
|
|
||||||
beforeLeave(el) {
|
|
||||||
this.leavingEl = el
|
|
||||||
},
|
|
||||||
// Transition when we leave the route
|
|
||||||
leave(el, done) {
|
|
||||||
const promise = this.transition(this.enteringEl, el)
|
|
||||||
|
|
||||||
this.inTransition = true
|
// Commit to the transition as soon as the Ionic Router Outlet is ready
|
||||||
|
return ionRouterOutlet.componentOnReady().then(el => {
|
||||||
|
return el.commit(enteringEl, leavingEl, {
|
||||||
|
deepWait: true,
|
||||||
|
duration: this.getDuration(),
|
||||||
|
direction: this.getDirection(),
|
||||||
|
showGoBack: this.$router.canGoBack(),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Skip any transition if we don't get back a Promise
|
// Instant transition if we don't want to animate
|
||||||
if (!promise) {
|
getDuration() {
|
||||||
this.inTransition = false
|
return !this.animated ? 0 : undefined;
|
||||||
return done()
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Perform navigation once the transition was finished
|
// Get the navigation direction from the router
|
||||||
return promise.then(() => {
|
getDirection() {
|
||||||
this.inTransition = false
|
return this.$router.direction === 1 ? 'forward' : 'back';
|
||||||
return done(true)
|
}
|
||||||
})
|
|
||||||
},
|
// Set the component to be rendered before we render the new route
|
||||||
// Enter the new route
|
beforeEnter(el: HTMLElement) {
|
||||||
enter(el, done) {
|
this.enteringEl = el;
|
||||||
done()
|
}
|
||||||
},
|
|
||||||
afterEnter(/* el */) {},
|
// Remember the current component before we leave the route
|
||||||
enterCancelled(/* el */) {},
|
beforeLeave(el: HTMLElement) {
|
||||||
afterLeave(/* el */) {},
|
this.leavingEl = el;
|
||||||
leaveCancelled(/* el */) {},
|
}
|
||||||
},
|
|
||||||
|
// Transition when we leave the route
|
||||||
|
leave(el: HTMLElement, done: (opts?: boolean) => void): void {
|
||||||
|
const promise = this.transition(this.enteringEl, el);
|
||||||
|
|
||||||
|
this.inTransition = true;
|
||||||
|
|
||||||
|
// Skip any transition if we don't get back a Promise
|
||||||
|
if (!promise) {
|
||||||
|
this.inTransition = false;
|
||||||
|
return done();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform navigation once the transition was finished
|
||||||
|
promise.then(() => {
|
||||||
|
this.inTransition = false;
|
||||||
|
return done(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter the new route
|
||||||
|
enter(_el: HTMLElement, done: () => void): void {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEnter(/* el */) {}
|
||||||
|
enterCancelled(/* el */) {}
|
||||||
|
afterLeave(/* el */) {}
|
||||||
|
leaveCancelled(/* el */) {}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
export default class Delegate {
|
|
||||||
constructor(Vue) {
|
|
||||||
this.Vue = Vue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attach the passed Vue component to DOM
|
|
||||||
attachViewToDom(parentElement, component, opts, classes) {
|
|
||||||
// Handle HTML elements
|
|
||||||
if (isElement(component)) {
|
|
||||||
// Add any classes to the element
|
|
||||||
addClasses(component, classes)
|
|
||||||
|
|
||||||
// Append the element to DOM
|
|
||||||
parentElement.appendChild(component)
|
|
||||||
return Promise.resolve(component)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the Vue controller
|
|
||||||
return this.vueController(component).then(controller => {
|
|
||||||
const vueComponent = this.vueComponent(controller, opts)
|
|
||||||
|
|
||||||
// Add any classes to the Vue component's root element
|
|
||||||
addClasses(vueComponent.$el, classes)
|
|
||||||
|
|
||||||
// Append the Vue component to DOM
|
|
||||||
parentElement.appendChild(vueComponent.$el)
|
|
||||||
return vueComponent.$el
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the earlier created Vue component from DOM
|
|
||||||
removeViewFromDom(parentElement, childElement) {
|
|
||||||
// Destroy the Vue component instance
|
|
||||||
if (childElement.__vue__) {
|
|
||||||
childElement.__vue__.$destroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.resolve()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle creation of sync and async components
|
|
||||||
vueController(component) {
|
|
||||||
return Promise.resolve(
|
|
||||||
typeof component === 'function' && component.cid === undefined
|
|
||||||
? component().then(c => this.Vue.extend(isESModule(c) ? c.default : c))
|
|
||||||
: this.Vue.extend(component)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new instance of the Vue component
|
|
||||||
vueComponent(controller, opts) {
|
|
||||||
return new controller(opts).$mount()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check Symbol support
|
|
||||||
const hasSymbol = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'
|
|
||||||
|
|
||||||
// Check if object is an ES module
|
|
||||||
function isESModule(obj) {
|
|
||||||
return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if value is an Element
|
|
||||||
function isElement(el) {
|
|
||||||
return typeof Element !== 'undefined' && el instanceof Element
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add an array of classes to an element
|
|
||||||
function addClasses(element, classes = []) {
|
|
||||||
for (const cls of classes) {
|
|
||||||
element.classList.add(cls)
|
|
||||||
}
|
|
||||||
}
|
|
75
vue/src/framework-delegate.ts
Normal file
75
vue/src/framework-delegate.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import { VueConstructor } from 'vue';
|
||||||
|
import { EsModule, FrameworkDelegate, HTMLVueElement, WebpackFunction } from './interfaces';
|
||||||
|
|
||||||
|
export default class Delegate implements FrameworkDelegate {
|
||||||
|
constructor(public vue: VueConstructor) {}
|
||||||
|
|
||||||
|
// Attach the passed Vue component to DOM
|
||||||
|
attachViewToDom(parentElement: HTMLElement, component: HTMLElement | WebpackFunction | object | VueConstructor, opts?: object, classes?: string[]): Promise<HTMLElement> {
|
||||||
|
// Handle HTML elements
|
||||||
|
if (isElement(component)) {
|
||||||
|
// Add any classes to the element
|
||||||
|
addClasses(component as HTMLElement, classes);
|
||||||
|
|
||||||
|
// Append the element to DOM
|
||||||
|
parentElement.appendChild(component as HTMLElement);
|
||||||
|
return Promise.resolve(component as HTMLElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Vue controller
|
||||||
|
return this.vueController(component).then((controller: VueConstructor) => {
|
||||||
|
const vueComponent = this.vueComponent(controller, opts);
|
||||||
|
|
||||||
|
// Add any classes to the Vue component's root element
|
||||||
|
addClasses(vueComponent.$el, classes);
|
||||||
|
|
||||||
|
// Append the Vue component to DOM
|
||||||
|
parentElement.appendChild(vueComponent.$el);
|
||||||
|
return vueComponent.$el;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the earlier created Vue component from DOM
|
||||||
|
removeViewFromDom(_parentElement: HTMLElement, childElement: HTMLVueElement): Promise<void> {
|
||||||
|
// Destroy the Vue component instance
|
||||||
|
if (childElement.__vue__) {
|
||||||
|
childElement.__vue__.$destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle creation of sync and async components
|
||||||
|
vueController(component: WebpackFunction | object | VueConstructor): Promise<VueConstructor> {
|
||||||
|
return Promise.resolve(
|
||||||
|
typeof component === 'function' && (component as WebpackFunction).cid === undefined
|
||||||
|
? (component as WebpackFunction)().then((cmp: any) => this.vue.extend(isESModule(cmp) ? cmp.default : cmp))
|
||||||
|
: this.vue.extend(component)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new instance of the Vue component
|
||||||
|
vueComponent(controller: VueConstructor, opts?: object) {
|
||||||
|
return new controller(opts).$mount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check Symbol support
|
||||||
|
const hasSymbol = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
|
||||||
|
|
||||||
|
// Check if object is an ES module
|
||||||
|
function isESModule(obj: EsModule) {
|
||||||
|
return obj.__esModule || (hasSymbol && obj[Symbol.toStringTag] === 'Module');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if value is an Element
|
||||||
|
function isElement(el: any) {
|
||||||
|
return typeof Element !== 'undefined' && el instanceof Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add an array of classes to an element
|
||||||
|
function addClasses(element: HTMLElement, classes: string[] = []) {
|
||||||
|
for (const cls of classes) {
|
||||||
|
element.classList.add(cls);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
export { default as Ionic } from './ionic'
|
|
||||||
export { default as IonicAPI } from './api'
|
|
||||||
export { default as IonicVueRouter } from './router'
|
|
3
vue/src/index.ts
Normal file
3
vue/src/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export { default as Ionic } from './ionic';
|
||||||
|
export { default as IonicAPI } from './api';
|
||||||
|
export { default as IonicVueRouter } from './router';
|
89
vue/src/interfaces.ts
Normal file
89
vue/src/interfaces.ts
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import IonicApi from './api';
|
||||||
|
import VueRouter from 'vue-router';
|
||||||
|
import { RouterOptions } from 'vue-router/types/router';
|
||||||
|
|
||||||
|
declare module 'vue/types/vue' {
|
||||||
|
interface Vue {
|
||||||
|
$ionic: IonicApi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'vue-router/types/router' {
|
||||||
|
interface VueRouter {
|
||||||
|
direction: number;
|
||||||
|
directionOverride: number | null;
|
||||||
|
canGoBack(): boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HTMLVueElement extends HTMLElement {
|
||||||
|
__vue__: Vue;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VueWindow extends Window {
|
||||||
|
Vue: typeof Vue;
|
||||||
|
VueRouter: typeof VueRouter;
|
||||||
|
disableIonicTransitions: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebpackFunction extends Function {
|
||||||
|
cid: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EsModule extends Object {
|
||||||
|
__esModule?: boolean;
|
||||||
|
[Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HTMLStencilElement extends HTMLElement {
|
||||||
|
componentOnReady(): Promise<this>;
|
||||||
|
componentOnReady(done: (el?: this) => void): void;
|
||||||
|
forceUpdate(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FrameworkDelegate {
|
||||||
|
attachViewToDom(parentElement: HTMLElement, component: HTMLElement | WebpackFunction | object | Vue, opts?: object, classes?: string[]): Promise<HTMLElement>;
|
||||||
|
removeViewFromDom(parentElement: HTMLElement, childElement: HTMLVueElement): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IonBackButton extends HTMLStencilElement {
|
||||||
|
defaultHref?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IonRouterOutlet extends HTMLStencilElement {
|
||||||
|
commit(enterinEl: HTMLElement, leavingEl: HTMLElement | undefined, opts?: object | undefined): Promise<boolean>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApiCache {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RouterArgs extends RouterOptions {
|
||||||
|
direction: number;
|
||||||
|
viewCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProxyControllerInterface {
|
||||||
|
create(opts: object): Promise<HTMLElement>;
|
||||||
|
dismiss(): Promise<void>;
|
||||||
|
getTop(): Promise<HTMLElement>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProxyDelegateOptions extends Object {
|
||||||
|
[key: string]: any;
|
||||||
|
delegate?: FrameworkDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProxyMenuControllerInterface {
|
||||||
|
open(menuId?: string): Promise<boolean>;
|
||||||
|
close(menuId?: string): Promise<boolean>;
|
||||||
|
toggle(menuId?: string): Promise<boolean>;
|
||||||
|
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement>;
|
||||||
|
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement>;
|
||||||
|
isOpen(menuId?: string): Promise<boolean>;
|
||||||
|
isEnabled(menuId?: string): Promise<boolean>;
|
||||||
|
get(menuId?: string): Promise<HTMLElement>;
|
||||||
|
getOpen(): Promise<HTMLElement>;
|
||||||
|
getMenus(): Promise<HTMLElement>;
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
import '@ionic/core/css/ionic.bundle.css'
|
|
||||||
import 'ionicons/dist/collection/icon/icon.css'
|
|
||||||
import '@ionic/core/dist/ionic/svg'
|
|
||||||
import { defineCustomElements } from '@ionic/core/loader'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
init(opts = {}) {
|
|
||||||
defineCustomElements(window, opts)
|
|
||||||
},
|
|
||||||
}
|
|
10
vue/src/ionic.ts
Normal file
10
vue/src/ionic.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import '@ionic/core/css/ionic.bundle.css';
|
||||||
|
import 'ionicons/dist/collection/icon/icon.css';
|
||||||
|
import '@ionic/core/dist/ionic/svg';
|
||||||
|
import { defineCustomElements } from '@ionic/core/loader';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init(): void {
|
||||||
|
defineCustomElements(window);
|
||||||
|
},
|
||||||
|
};
|
@ -1,27 +0,0 @@
|
|||||||
export default {
|
|
||||||
methods: {
|
|
||||||
// Catch the bubbled-up event from the Ionic's back button
|
|
||||||
catchIonicGoBack(event) {
|
|
||||||
// We only care for the event coming from Ionic's back button
|
|
||||||
const backButton = event.target && event.target.closest('ion-back-button')
|
|
||||||
if (!backButton) return
|
|
||||||
|
|
||||||
let defaultHref
|
|
||||||
|
|
||||||
// Explicitly override router direction
|
|
||||||
// This will always trigger a back transition
|
|
||||||
this.$router.directionOverride = -1
|
|
||||||
|
|
||||||
// If we can go back - do so
|
|
||||||
// otherwise if there's a default fall-back - use it
|
|
||||||
// else - skip
|
|
||||||
if (this.$router.canGoBack()) {
|
|
||||||
event.preventDefault()
|
|
||||||
this.$router.back()
|
|
||||||
} else if (undefined !== (defaultHref = backButton.defaultHref)) {
|
|
||||||
event.preventDefault()
|
|
||||||
this.$router.push(defaultHref)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
36
vue/src/mixins/catch-ionic-go-back.ts
Normal file
36
vue/src/mixins/catch-ionic-go-back.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import Router from '../router';
|
||||||
|
import Component from 'vue-class-component';
|
||||||
|
import { IonBackButton } from '../interfaces';
|
||||||
|
|
||||||
|
@Component
|
||||||
|
export default class CatchIonicGoBack extends Vue {
|
||||||
|
// Catch the bubbled-up event from the Ionic's back button
|
||||||
|
catchIonicGoBack(event: Event): void {
|
||||||
|
if (!event.target) return;
|
||||||
|
|
||||||
|
// We only care for the event coming from Ionic's back button
|
||||||
|
const backButton = (event.target as HTMLElement).closest('ion-back-button') as IonBackButton;
|
||||||
|
if (!backButton) return;
|
||||||
|
|
||||||
|
const $router = this.$router as Router;
|
||||||
|
let defaultHref: string;
|
||||||
|
|
||||||
|
// Explicitly override router direction to always trigger a back transition
|
||||||
|
$router.directionOverride = -1;
|
||||||
|
|
||||||
|
// If we can go back - do so
|
||||||
|
if ($router.canGoBack()) {
|
||||||
|
event.preventDefault();
|
||||||
|
$router.back();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's a default fallback - use it
|
||||||
|
defaultHref = backButton.defaultHref as string;
|
||||||
|
if (undefined !== defaultHref) {
|
||||||
|
event.preventDefault();
|
||||||
|
$router.push(defaultHref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +0,0 @@
|
|||||||
import * as apiUtils from './api-utils'
|
|
||||||
|
|
||||||
// A proxy class that allows early access to controller methods
|
|
||||||
export default class ProxyController {
|
|
||||||
constructor(tag) {
|
|
||||||
this.tag = tag
|
|
||||||
}
|
|
||||||
|
|
||||||
create(opts = {}) {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'create', opts)
|
|
||||||
}
|
|
||||||
|
|
||||||
dismiss() {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'dismiss')
|
|
||||||
}
|
|
||||||
|
|
||||||
getTop() {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'getTop')
|
|
||||||
}
|
|
||||||
}
|
|
19
vue/src/proxy-controller.ts
Normal file
19
vue/src/proxy-controller.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import * as apiUtils from './api-utils';
|
||||||
|
import { ProxyControllerInterface } from './interfaces';
|
||||||
|
|
||||||
|
// A proxy class that allows early access to controller methods
|
||||||
|
export default class ProxyController implements ProxyControllerInterface {
|
||||||
|
constructor(public tag: string) {}
|
||||||
|
|
||||||
|
create(opts: object = {}): Promise<HTMLElement> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'create', opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
dismiss(): Promise<void> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'dismiss');
|
||||||
|
}
|
||||||
|
|
||||||
|
getTop(): Promise<HTMLElement> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'getTop');
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
import ProxyController from './proxy-controller'
|
|
||||||
|
|
||||||
// A proxy class that allows early access to controller methods
|
|
||||||
export default class ProxyDelegateController extends ProxyController {
|
|
||||||
constructor(tag, delegate) {
|
|
||||||
super(tag)
|
|
||||||
|
|
||||||
if (!ProxyDelegateController.delegate) {
|
|
||||||
ProxyDelegateController.delegate = delegate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
create(opts = {}) {
|
|
||||||
opts.delegate = ProxyDelegateController.delegate
|
|
||||||
return super.create(opts)
|
|
||||||
}
|
|
||||||
}
|
|
20
vue/src/proxy-delegate-controller.ts
Normal file
20
vue/src/proxy-delegate-controller.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import ProxyController from './proxy-controller';
|
||||||
|
import { FrameworkDelegate, ProxyDelegateOptions } from './interfaces';
|
||||||
|
|
||||||
|
// A proxy class that allows early access to controller methods
|
||||||
|
export default class ProxyDelegateController extends ProxyController {
|
||||||
|
static delegate: FrameworkDelegate;
|
||||||
|
|
||||||
|
constructor(public tag: string, delegate: FrameworkDelegate) {
|
||||||
|
super(tag);
|
||||||
|
|
||||||
|
if (!ProxyDelegateController.delegate) {
|
||||||
|
ProxyDelegateController.delegate = delegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
create(opts: ProxyDelegateOptions = {} as ProxyDelegateOptions) {
|
||||||
|
opts.delegate = ProxyDelegateController.delegate;
|
||||||
|
return super.create(opts);
|
||||||
|
}
|
||||||
|
}
|
@ -1,58 +0,0 @@
|
|||||||
import * as apiUtils from './api-utils'
|
|
||||||
|
|
||||||
// A proxy class that allows early access to controller methods
|
|
||||||
export default class ProxyMenuController {
|
|
||||||
constructor(tag) {
|
|
||||||
this.tag = tag
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open a menu
|
|
||||||
open(menuId) {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'open', menuId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close a menu
|
|
||||||
close(menuId) {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'close', menuId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Toggle a menu
|
|
||||||
toggle(menuId) {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'toggle', menuId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable or disable a menu
|
|
||||||
enable(shouldEnable, menuId) {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'enable', shouldEnable, menuId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enable or disable the ability to swipe open the menu
|
|
||||||
swipeEnable(shouldEnable, menuId) {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'swipeEnable', shouldEnable, menuId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if specific or any menu is open
|
|
||||||
isOpen(menuId) {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'isOpen', menuId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check is certain menu is enabled
|
|
||||||
isEnabled(menuId) {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'isEnabled', menuId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get specific or first menu instance
|
|
||||||
get(menuId) {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'get', menuId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get an instance of an open menu
|
|
||||||
getOpen() {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'getOpen')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get an array of all menus
|
|
||||||
getMenus() {
|
|
||||||
return apiUtils.proxyMethod(this.tag, 'getMenus')
|
|
||||||
}
|
|
||||||
}
|
|
57
vue/src/proxy-menu-controller.ts
Normal file
57
vue/src/proxy-menu-controller.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import * as apiUtils from './api-utils';
|
||||||
|
import { ProxyMenuControllerInterface } from './interfaces';
|
||||||
|
|
||||||
|
// A proxy class that allows early access to controller methods
|
||||||
|
export default class ProxyMenuController implements ProxyMenuControllerInterface {
|
||||||
|
constructor(public tag: string) {}
|
||||||
|
|
||||||
|
// Open a menu
|
||||||
|
open(menuId?: string): Promise<boolean> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'open', menuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close a menu
|
||||||
|
close(menuId?: string): Promise<boolean> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'close', menuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle a menu
|
||||||
|
toggle(menuId?: string): Promise<boolean> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'toggle', menuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable or disable a menu
|
||||||
|
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'enable', shouldEnable, menuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable or disable the ability to swipe open the menu
|
||||||
|
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'swipeEnable', shouldEnable, menuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if specific or any menu is open
|
||||||
|
isOpen(menuId?: string): Promise<boolean> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'isOpen', menuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check is certain menu is enabled
|
||||||
|
isEnabled(menuId?: string): Promise<boolean> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'isEnabled', menuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get specific or first menu instance
|
||||||
|
get(menuId?: string): Promise<HTMLElement> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'get', menuId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an instance of an open menu
|
||||||
|
getOpen(): Promise<HTMLElement> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'getOpen');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an array of all menus
|
||||||
|
getMenus(): Promise<HTMLElement> {
|
||||||
|
return apiUtils.proxyMethod(this.tag, 'getMenus');
|
||||||
|
}
|
||||||
|
}
|
@ -1,101 +0,0 @@
|
|||||||
import VueRouter from 'vue-router'
|
|
||||||
import IonVueRouter from './components/ion-vue-router.vue'
|
|
||||||
import IonVueRouterTransitionless from './components/ion-vue-router-transitionless.vue'
|
|
||||||
|
|
||||||
const inBrowser = typeof window !== 'undefined'
|
|
||||||
|
|
||||||
// Detect environment (browser, module, etc.)
|
|
||||||
const _VueRouter = inBrowser && window.VueRouter ? window.VueRouter : VueRouter
|
|
||||||
|
|
||||||
// Extend the official VueRouter
|
|
||||||
export default class Router extends _VueRouter {
|
|
||||||
constructor(...args) {
|
|
||||||
super(...args)
|
|
||||||
|
|
||||||
// The direction user navigates in
|
|
||||||
this.direction = args.direction || 1
|
|
||||||
|
|
||||||
// Override normal direction
|
|
||||||
this.directionOverride = null
|
|
||||||
|
|
||||||
// Number of views navigated
|
|
||||||
this.viewCount = args.viewCount || 0
|
|
||||||
|
|
||||||
// Stack of previous routes
|
|
||||||
this.prevRouteStack = []
|
|
||||||
|
|
||||||
// Extend the existing history object
|
|
||||||
this.extendHistory()
|
|
||||||
}
|
|
||||||
extendHistory() {
|
|
||||||
// Save a reference to the original method
|
|
||||||
this.history._updateRoute = this.history.updateRoute
|
|
||||||
|
|
||||||
this.history.updateRoute = nextRoute => {
|
|
||||||
// Guesstimate the direction of the next route
|
|
||||||
this.direction = this.guessDirection(nextRoute)
|
|
||||||
|
|
||||||
// Override the direction
|
|
||||||
if (this.directionOverride) {
|
|
||||||
this.direction = this.directionOverride
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment or decrement the view count
|
|
||||||
this.viewCount += this.direction
|
|
||||||
|
|
||||||
// Call the original method
|
|
||||||
this.history._updateRoute(nextRoute)
|
|
||||||
|
|
||||||
// Reset direction for overrides
|
|
||||||
this.directionOverride = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
canGoBack() {
|
|
||||||
// We can display the back button if we're not on /
|
|
||||||
// or there were more than 1 views rendered
|
|
||||||
return this.viewCount > 1 && this.currentRoute.fullPath.length > 1
|
|
||||||
}
|
|
||||||
guessDirection(nextRoute) {
|
|
||||||
if (this.prevRouteStack.length !== 0) {
|
|
||||||
const prevRoute = this.prevRouteStack[this.prevRouteStack.length - 1]
|
|
||||||
|
|
||||||
// Last route is the same as the next one - go back
|
|
||||||
// If we're going to / reset the stack otherwise pop a route
|
|
||||||
if (prevRoute.fullPath === nextRoute.fullPath) {
|
|
||||||
if (prevRoute.fullPath.length === 1) {
|
|
||||||
this.prevRouteStack = []
|
|
||||||
} else {
|
|
||||||
this.prevRouteStack.pop()
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward movement, push next route to stack
|
|
||||||
if (this.history.current.fullPath !== nextRoute.fullPath) {
|
|
||||||
this.prevRouteStack.push(this.history.current)
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Router.install = function(Vue, { disableIonicTransitions } = {}) {
|
|
||||||
// If already installed - skip
|
|
||||||
if (Router.install.installed) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Router.install.installed = true
|
|
||||||
|
|
||||||
// Install the official VueRouter
|
|
||||||
_VueRouter.install(Vue)
|
|
||||||
|
|
||||||
// Register the IonVueRouter component globally
|
|
||||||
// either with default Ionic transitions turned on or off
|
|
||||||
Vue.component('IonVueRouter', disableIonicTransitions ? IonVueRouterTransitionless : IonVueRouter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-install when Vue is found (i.e. in browser via <script> tag)
|
|
||||||
if (inBrowser && window.Vue) {
|
|
||||||
window.Vue.use(Router, { disableIonicTransitions: window.disableIonicTransitions })
|
|
||||||
}
|
|
115
vue/src/router.ts
Normal file
115
vue/src/router.ts
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import VueRouter, { Route } from 'vue-router';
|
||||||
|
import { PluginFunction } from 'vue';
|
||||||
|
import { RouterArgs, VueWindow } from './interfaces';
|
||||||
|
import IonVueRouter from './components/ion-vue-router.vue';
|
||||||
|
import IonVueRouterTransitionless from './components/ion-vue-router-transitionless.vue';
|
||||||
|
|
||||||
|
const vueWindow = window as VueWindow;
|
||||||
|
const inBrowser: boolean = typeof window !== 'undefined';
|
||||||
|
|
||||||
|
// Detect environment (browser, module, etc.)
|
||||||
|
const _VueRouter: typeof VueRouter = inBrowser && vueWindow.VueRouter ? vueWindow.VueRouter : VueRouter;
|
||||||
|
|
||||||
|
// Extend the official VueRouter
|
||||||
|
export default class Router extends _VueRouter {
|
||||||
|
direction: number;
|
||||||
|
directionOverride: number | null;
|
||||||
|
viewCount: number;
|
||||||
|
prevRouteStack: Route[];
|
||||||
|
history: any;
|
||||||
|
static installed: boolean;
|
||||||
|
static install: PluginFunction<never>;
|
||||||
|
|
||||||
|
constructor(args: RouterArgs = {} as RouterArgs) {
|
||||||
|
super(args);
|
||||||
|
|
||||||
|
// The direction user navigates in
|
||||||
|
this.direction = args.direction || 1;
|
||||||
|
|
||||||
|
// Override normal direction
|
||||||
|
this.directionOverride = null;
|
||||||
|
|
||||||
|
// Number of views navigated
|
||||||
|
this.viewCount = args.viewCount || 0;
|
||||||
|
|
||||||
|
// Stack of previous routes
|
||||||
|
this.prevRouteStack = [];
|
||||||
|
|
||||||
|
// Extend the existing history object
|
||||||
|
this.extendHistory();
|
||||||
|
}
|
||||||
|
|
||||||
|
extendHistory(): void {
|
||||||
|
// Save a reference to the original method
|
||||||
|
this.history._updateRoute = this.history.updateRoute;
|
||||||
|
|
||||||
|
this.history.updateRoute = (nextRoute: Route) => {
|
||||||
|
// Guesstimate the direction of the next route
|
||||||
|
this.direction = this.guessDirection(nextRoute);
|
||||||
|
|
||||||
|
// Override the direction
|
||||||
|
if (this.directionOverride) {
|
||||||
|
this.direction = this.directionOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increment or decrement the view count
|
||||||
|
this.viewCount += this.direction;
|
||||||
|
|
||||||
|
// Call the original method
|
||||||
|
this.history._updateRoute(nextRoute);
|
||||||
|
|
||||||
|
// Reset direction for overrides
|
||||||
|
this.directionOverride = null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
canGoBack(): boolean {
|
||||||
|
// We can display the back button if we're not on /
|
||||||
|
// or there were more than 1 views rendered
|
||||||
|
return this.viewCount > 1 && this.currentRoute.fullPath.length > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
guessDirection(nextRoute: Route): number {
|
||||||
|
if (this.prevRouteStack.length !== 0) {
|
||||||
|
const prevRoute: Route = this.prevRouteStack[this.prevRouteStack.length - 1];
|
||||||
|
|
||||||
|
// Last route is the same as the next one - go back
|
||||||
|
// If we're going to / reset the stack otherwise pop a route
|
||||||
|
if (prevRoute.fullPath === nextRoute.fullPath) {
|
||||||
|
if (prevRoute.fullPath.length === 1) {
|
||||||
|
this.prevRouteStack = [];
|
||||||
|
} else {
|
||||||
|
this.prevRouteStack.pop();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward movement, push next route to stack
|
||||||
|
if (this.history.current.fullPath !== nextRoute.fullPath) {
|
||||||
|
this.prevRouteStack.push(this.history.current);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Router.install = (Vue, { disableIonicTransitions = false }: { disableIonicTransitions?: boolean } = {}): void => {
|
||||||
|
// If already installed - skip
|
||||||
|
if (Router.installed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Router.installed = true;
|
||||||
|
|
||||||
|
// Install the official VueRouter
|
||||||
|
_VueRouter.install(Vue);
|
||||||
|
|
||||||
|
// Register the IonVueRouter component globally
|
||||||
|
// either with default Ionic transitions turned on or off
|
||||||
|
Vue.component('IonVueRouter', disableIonicTransitions ? IonVueRouterTransitionless : IonVueRouter);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Auto-install when Vue is found (i.e. in browser via <script> tag)
|
||||||
|
if (inBrowser && vueWindow.Vue) {
|
||||||
|
vueWindow.Vue.use(Router, { disableIonicTransitions: vueWindow.disableIonicTransitions });
|
||||||
|
}
|
4
vue/src/sfc.d.ts
vendored
Normal file
4
vue/src/sfc.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
declare module '*.vue' {
|
||||||
|
import Vue from 'vue';
|
||||||
|
export default Vue;
|
||||||
|
}
|
@ -1,184 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import API from '../src/api.js'
|
|
||||||
|
|
||||||
const api = new API()
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
HTMLElement.prototype.componentOnReady = function() {
|
|
||||||
const el = this
|
|
||||||
el.create = function(props = {}) {
|
|
||||||
return Object.assign(el, props)
|
|
||||||
}
|
|
||||||
el.dismiss = function() {
|
|
||||||
return el
|
|
||||||
}
|
|
||||||
el.getTop = el.dismiss
|
|
||||||
el.open = el.create
|
|
||||||
el.close = el.dismiss
|
|
||||||
el.toggle = el.dismiss
|
|
||||||
el.enable = el.dismiss
|
|
||||||
el.swipeEnable = el.dismiss
|
|
||||||
el.isOpen = el.dismiss
|
|
||||||
el.isEnabled = el.dismiss
|
|
||||||
el.get = el.dismiss
|
|
||||||
el.getOpen = el.dismiss
|
|
||||||
el.getMenus = el.dismiss
|
|
||||||
|
|
||||||
return Promise.resolve(el)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
HTMLElement.prototype.componentOnReady = undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('API', () => {
|
|
||||||
it('Installs correctly', () => {
|
|
||||||
Vue.use(API)
|
|
||||||
|
|
||||||
const app = new Vue()
|
|
||||||
|
|
||||||
expect(typeof app.$ionic).toBe('object')
|
|
||||||
expect(API.install(Vue)).toBeFalsy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Creates action sheet controller', () => {
|
|
||||||
expect.assertions(3)
|
|
||||||
|
|
||||||
api.actionSheetController
|
|
||||||
.dismiss()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
api.actionSheetController
|
|
||||||
.getTop()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
return api.actionSheetController.create().then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Creates alert controllers', () => {
|
|
||||||
expect.assertions(3)
|
|
||||||
|
|
||||||
// Creates initial element
|
|
||||||
api.alertController
|
|
||||||
.create({ foo: 'bar' })
|
|
||||||
.then(c => {
|
|
||||||
return expect(c.foo).toBe('bar')
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
// Returns previous element with extra props
|
|
||||||
return api.alertController.create({ bar: 'foo' }).then(c => {
|
|
||||||
expect(c.foo).toBe('bar')
|
|
||||||
return expect(c.bar).toBe('foo')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Creates loading controllers', done => {
|
|
||||||
return api.loadingController.create({ bar: 'foo' }).then(c => {
|
|
||||||
expect(c.bar).toBe('foo')
|
|
||||||
return done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Creates modal controllers', done => {
|
|
||||||
return api.modalController.create({ bar: 'foo' }).then(c => {
|
|
||||||
expect(c.bar).toBe('foo')
|
|
||||||
return done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Creates popover controllers', done => {
|
|
||||||
return api.popoverController.create({ bar: 'foo' }).then(c => {
|
|
||||||
expect(c.bar).toBe('foo')
|
|
||||||
return done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Creates toast controllers', done => {
|
|
||||||
return api.toastController.create({ bar: 'foo' }).then(c => {
|
|
||||||
expect(c.bar).toBe('foo')
|
|
||||||
return done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Creates menu controllers', done => {
|
|
||||||
expect.assertions(10)
|
|
||||||
|
|
||||||
api.menuController
|
|
||||||
.close()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
api.menuController
|
|
||||||
.toggle()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
api.menuController
|
|
||||||
.enable()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
api.menuController
|
|
||||||
.swipeEnable()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
api.menuController
|
|
||||||
.isOpen()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
api.menuController
|
|
||||||
.isEnabled()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
api.menuController
|
|
||||||
.get()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
api.menuController
|
|
||||||
.getOpen()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
api.menuController
|
|
||||||
.getMenus()
|
|
||||||
.then(c => {
|
|
||||||
return expect(c).toBeTruthy()
|
|
||||||
})
|
|
||||||
.catch(err => err)
|
|
||||||
|
|
||||||
return api.menuController.open({ bar: 'foo' }).then(c => {
|
|
||||||
expect(c.bar).toBe('foo')
|
|
||||||
return done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,73 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import Delegate from '../src/framework-delegate.js'
|
|
||||||
|
|
||||||
const delegate = new Delegate(Vue)
|
|
||||||
|
|
||||||
const app = document.createElement('div')
|
|
||||||
app.id = 'app'
|
|
||||||
document.body.appendChild(app)
|
|
||||||
|
|
||||||
describe('Framework delegation', () => {
|
|
||||||
it('Attaches components to DOM', () => {
|
|
||||||
expect.assertions(2)
|
|
||||||
|
|
||||||
const component = {
|
|
||||||
template: '<p>foo</p>',
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
data() {
|
|
||||||
return { foo: 'bar' }
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return delegate.attachViewToDom(app, component, data, ['foo']).then(el => {
|
|
||||||
expect(el.classList.contains('foo')).toBeTruthy()
|
|
||||||
expect(el.__vue__.foo).toBe('bar')
|
|
||||||
return
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Attaches lazy loaded components to DOM', () => {
|
|
||||||
expect.assertions(2)
|
|
||||||
|
|
||||||
const component = function() {
|
|
||||||
return Promise.resolve({
|
|
||||||
render(h) {
|
|
||||||
return h('p')
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
data() {
|
|
||||||
return { foo: 'bar' }
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return delegate.attachViewToDom(app, component, data, ['foo']).then(el => {
|
|
||||||
expect(el.classList.contains('foo')).toBeTruthy()
|
|
||||||
expect(el.__vue__.foo).toBe('bar')
|
|
||||||
return
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Attaches HTML elements to DOM', () => {
|
|
||||||
expect.assertions(1)
|
|
||||||
const element = document.createElement('p')
|
|
||||||
|
|
||||||
return delegate.attachViewToDom(app, element, null, ['foo']).then(el => {
|
|
||||||
return expect(el.classList.contains('foo')).toBeTruthy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Removes from DOM', () => {
|
|
||||||
expect.assertions(2)
|
|
||||||
const div = document.querySelector('p')
|
|
||||||
expect(typeof div.__vue__).toBe('object')
|
|
||||||
|
|
||||||
return delegate.removeViewFromDom(app, div).then(() => {
|
|
||||||
return expect(div.__vue__).toBe(null)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,43 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import Router from '../src/router.js'
|
|
||||||
import IonVueRouterTransitionless from '../src/components/ion-vue-router-transitionless.vue'
|
|
||||||
|
|
||||||
Vue.use(Router)
|
|
||||||
|
|
||||||
describe('IonVueRouter', () => {
|
|
||||||
it('Catches back button click event', () => {
|
|
||||||
const constructor = Vue.extend(IonVueRouterTransitionless)
|
|
||||||
const component = new constructor({ router: new Router({ mode: 'abstract' }) })
|
|
||||||
|
|
||||||
expect(component.catchIonicGoBack({})).toBeFalsy()
|
|
||||||
|
|
||||||
component.$router.push('/')
|
|
||||||
component.$router.push('/foo')
|
|
||||||
expect(component.$route.fullPath).toBe('/foo')
|
|
||||||
|
|
||||||
// Go back
|
|
||||||
component.catchIonicGoBack(mockBackEvent('/'))
|
|
||||||
expect(component.$route.fullPath).toBe('/')
|
|
||||||
|
|
||||||
// Should not go back
|
|
||||||
component.catchIonicGoBack(mockBackEvent())
|
|
||||||
expect(component.$route.fullPath).toBe('/')
|
|
||||||
|
|
||||||
// Go back to default route
|
|
||||||
component.catchIonicGoBack(mockBackEvent('/bar'))
|
|
||||||
expect(component.$route.fullPath).toBe('/bar')
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function mockBackEvent(route) {
|
|
||||||
return {
|
|
||||||
target: {
|
|
||||||
closest() {
|
|
||||||
return {
|
|
||||||
defaultHref: route,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
preventDefault() {},
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import Router from '../src/router.js'
|
|
||||||
import IonVueRouter from '../src/components/ion-vue-router.vue'
|
|
||||||
|
|
||||||
describe('IonVueRouter', () => {
|
|
||||||
Vue.use(Router)
|
|
||||||
Vue.config.ignoredElements.push(/^ion-/)
|
|
||||||
|
|
||||||
const app = new Vue({
|
|
||||||
components: { Toolbar: Toolbar() },
|
|
||||||
render(h) {
|
|
||||||
return h('ion-vue-router')
|
|
||||||
},
|
|
||||||
router: new Router({
|
|
||||||
mode: 'abstract',
|
|
||||||
routes: [{ path: '/', component: Home() }, { path: '/page', component: Page() }],
|
|
||||||
}),
|
|
||||||
}).$mount()
|
|
||||||
|
|
||||||
it('Renders the home route correctly', done => {
|
|
||||||
app.$router.push('/')
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(app.$el.textContent.trim()).toBe('Home Go to page')
|
|
||||||
done()
|
|
||||||
}, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Renders the page route correctly', done => {
|
|
||||||
app.$router.push('/page')
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(app.$el.textContent.trim()).toBe('Page Go home')
|
|
||||||
done()
|
|
||||||
}, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Renders back route correctly', done => {
|
|
||||||
app.$router.go(-1)
|
|
||||||
setTimeout(() => {
|
|
||||||
expect(app.$el.textContent.trim()).toBe('Home Go to page')
|
|
||||||
done()
|
|
||||||
}, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Sets the default data correctly', () => {
|
|
||||||
expect(typeof IonVueRouter.data).toBe('function')
|
|
||||||
expect(IonVueRouter.data()).toMatchObject({
|
|
||||||
leavingEl: null,
|
|
||||||
enteringEl: null,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Sets the default props correctly', () => {
|
|
||||||
const constructor = Vue.extend(IonVueRouter)
|
|
||||||
const component = new constructor({ router: new Router() })
|
|
||||||
expect(component.bindCss).toBeFalsy()
|
|
||||||
expect(component.animated).toBeTruthy()
|
|
||||||
expect(component.name).toBe('default')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Transitions correctly', () => {
|
|
||||||
expect.assertions(3)
|
|
||||||
|
|
||||||
const constructor = Vue.extend(IonVueRouter)
|
|
||||||
const component = new constructor({ router: new Router() })
|
|
||||||
|
|
||||||
component.$refs.ionRouterOutlet = mockIonRouterOutlet()
|
|
||||||
expect(component.transition()).toBeFalsy()
|
|
||||||
|
|
||||||
component.enteringEl = document.createElement('div')
|
|
||||||
component.leave(document.createElement('h1'), res => {
|
|
||||||
expect(res).toBeTruthy()
|
|
||||||
})
|
|
||||||
|
|
||||||
return component
|
|
||||||
.transition(document.createElement('div'), document.createElement('h1'))
|
|
||||||
.then(res => {
|
|
||||||
return expect(res).toBeTruthy()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Gets duration correctly', () => {
|
|
||||||
const constructor = Vue.extend(IonVueRouter)
|
|
||||||
const component = new constructor({ router: new Router() })
|
|
||||||
|
|
||||||
expect(component.getDuration()).toBe(undefined)
|
|
||||||
|
|
||||||
component.animated = false
|
|
||||||
expect(component.getDuration()).toBe(0)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Gets direction correctly', () => {
|
|
||||||
const constructor = Vue.extend(IonVueRouter)
|
|
||||||
const component = new constructor({ router: new Router() })
|
|
||||||
|
|
||||||
expect(component.getDirection()).toBe('forward')
|
|
||||||
|
|
||||||
component.$router.direction = -1
|
|
||||||
expect(component.getDirection()).toBe('back')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Runs stub methods correctly', () => {
|
|
||||||
const constructor = Vue.extend(IonVueRouter)
|
|
||||||
const component = new constructor({ router: new Router() })
|
|
||||||
|
|
||||||
component.enterCancelled()
|
|
||||||
component.leaveCancelled()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
function Toolbar() {
|
|
||||||
return Vue.component('Toolbar', {
|
|
||||||
name: 'Toolbar',
|
|
||||||
props: {
|
|
||||||
backURL: { type: String, default: '' },
|
|
||||||
title: { type: String, default: '' },
|
|
||||||
},
|
|
||||||
template: `
|
|
||||||
<ion-header>
|
|
||||||
<ion-toolbar>
|
|
||||||
<ion-buttons slot="start">
|
|
||||||
<ion-back-button :default-href="backURL"/>
|
|
||||||
</ion-buttons>
|
|
||||||
<ion-title>{{ title }}</ion-title>
|
|
||||||
</ion-toolbar>
|
|
||||||
</ion-header>`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function Home() {
|
|
||||||
return Vue.component('Home', {
|
|
||||||
template: `
|
|
||||||
<ion-page class="ion-page">
|
|
||||||
<toolbar title="Home"/>
|
|
||||||
<ion-content class="ion-content" padding>
|
|
||||||
<router-link to="/page">Go to page</router-link>
|
|
||||||
</ion-content>
|
|
||||||
</ion-page>`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function Page() {
|
|
||||||
return Vue.component('Page', {
|
|
||||||
methods: {
|
|
||||||
goHome() {
|
|
||||||
this.$router.back()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
template: `
|
|
||||||
<ion-page class="ion-page">
|
|
||||||
<toolbar title="Page"/>
|
|
||||||
<ion-content class="ion-content" padding>
|
|
||||||
<ion-button @click="goHome">Go home</ion-button>
|
|
||||||
</ion-content>
|
|
||||||
</ion-page>`,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function mockIonRouterOutlet() {
|
|
||||||
return {
|
|
||||||
componentOnReady() {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
return resolve({
|
|
||||||
commit() {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
|
|
||||||
describe('Router node', () => {
|
|
||||||
it('Sets globals correctly', () => {
|
|
||||||
window.Vue = undefined
|
|
||||||
global.Vue = Vue
|
|
||||||
require('../src/router.js')
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,45 +0,0 @@
|
|||||||
import Vue from 'vue'
|
|
||||||
import Router from '../src/router.js'
|
|
||||||
|
|
||||||
describe('Router', () => {
|
|
||||||
it('Installs correctly', () => {
|
|
||||||
Vue.use(Router)
|
|
||||||
|
|
||||||
const app = new Vue({
|
|
||||||
router: new Router(),
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(typeof app.$router).toBe('object')
|
|
||||||
expect(typeof app.$options.components.IonVueRouter).toBe('function')
|
|
||||||
expect(Router.install()).toBeFalsy()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Navigates correctly', () => {
|
|
||||||
const r = new Router({ mode: 'abstract' })
|
|
||||||
|
|
||||||
r.push('/')
|
|
||||||
expect(r.viewCount).toBe(1)
|
|
||||||
expect(r.direction).toBe(1)
|
|
||||||
expect(r.canGoBack()).toBeFalsy()
|
|
||||||
|
|
||||||
r.push('/foo')
|
|
||||||
expect(r.viewCount).toBe(2)
|
|
||||||
expect(r.direction).toBe(1)
|
|
||||||
expect(r.canGoBack()).toBeTruthy()
|
|
||||||
|
|
||||||
r.push('/bar')
|
|
||||||
expect(r.viewCount).toBe(3)
|
|
||||||
expect(r.direction).toBe(1)
|
|
||||||
expect(r.canGoBack()).toBeTruthy()
|
|
||||||
|
|
||||||
r.go(-1)
|
|
||||||
expect(r.viewCount).toBe(2)
|
|
||||||
expect(r.direction).toBe(-1)
|
|
||||||
expect(r.canGoBack()).toBeTruthy()
|
|
||||||
|
|
||||||
r.go(-1)
|
|
||||||
expect(r.viewCount).toBe(1)
|
|
||||||
expect(r.direction).toBe(-1)
|
|
||||||
expect(r.canGoBack()).toBeFalsy()
|
|
||||||
})
|
|
||||||
})
|
|
37
vue/tsconfig.json
Normal file
37
vue/tsconfig.json
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"alwaysStrict": true,
|
||||||
|
"strict": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"allowUnreachableCode": false,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"declarationDir": "types",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"jsx": "react",
|
||||||
|
"jsxFactory": "h",
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"es2017"
|
||||||
|
],
|
||||||
|
"module": "es2015",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"pretty": true,
|
||||||
|
"removeComments": false,
|
||||||
|
"rootDir": "src",
|
||||||
|
"strictPropertyInitialization": false,
|
||||||
|
"target": "es5"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
7
vue/tslint.json
Normal file
7
vue/tslint.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"extends": "tslint-ionic-rules",
|
||||||
|
"rules": {
|
||||||
|
"no-non-null-assertion": false,
|
||||||
|
"no-import-side-effect": [true, {"ignore-module": "(svg|\\.css)$"}]
|
||||||
|
}
|
||||||
|
}
|
4
vue/types/api-utils.d.ts
vendored
Normal file
4
vue/types/api-utils.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { HTMLStencilElement } from './interfaces';
|
||||||
|
export declare function proxyMethod(tag: string, method: string, ...opts: any[]): Promise<any>;
|
||||||
|
export declare function initController(tag: string): Promise<HTMLStencilElement>;
|
||||||
|
//# sourceMappingURL=api-utils.d.ts.map
|
18
vue/types/api.d.ts
vendored
Normal file
18
vue/types/api.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { PluginFunction } from 'vue';
|
||||||
|
import { ApiCache } from './interfaces';
|
||||||
|
import ProxyController from './proxy-controller';
|
||||||
|
import ProxyMenuController from './proxy-menu-controller';
|
||||||
|
import ProxyDelegateController from './proxy-delegate-controller';
|
||||||
|
export default class Api {
|
||||||
|
static cache: ApiCache;
|
||||||
|
static installed: boolean;
|
||||||
|
static install: PluginFunction<never>;
|
||||||
|
readonly actionSheetController: ProxyController;
|
||||||
|
readonly alertController: ProxyController;
|
||||||
|
readonly loadingController: ProxyController;
|
||||||
|
readonly menuController: ProxyMenuController;
|
||||||
|
readonly modalController: ProxyDelegateController;
|
||||||
|
readonly popoverController: ProxyDelegateController;
|
||||||
|
readonly toastController: ProxyController;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=api.d.ts.map
|
7
vue/types/components/ion-vue-router-transitionless.vue.d.ts
vendored
Normal file
7
vue/types/components/ion-vue-router-transitionless.vue.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import CatchIonicGoBack from '../mixins/catch-ionic-go-back';
|
||||||
|
declare const IonVueRouter_base: import("vue-class-component/lib/declarations").VueClass<CatchIonicGoBack>;
|
||||||
|
export default class IonVueRouter extends IonVueRouter_base {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
|
//# sourceMappingURL=ion-vue-router-transitionless.vue?rollup-plugin-vue=script.d.ts.map
|
25
vue/types/components/ion-vue-router.vue.d.ts
vendored
Normal file
25
vue/types/components/ion-vue-router.vue.d.ts
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import CatchIonicGoBack from '../mixins/catch-ionic-go-back';
|
||||||
|
declare const IonVueRouter_base: import("vue-class-component/lib/declarations").VueClass<CatchIonicGoBack>;
|
||||||
|
export default class IonVueRouter extends IonVueRouter_base {
|
||||||
|
name: string;
|
||||||
|
bindCSS: boolean;
|
||||||
|
animated: boolean;
|
||||||
|
leavingEl: HTMLElement;
|
||||||
|
enteringEl: HTMLElement;
|
||||||
|
inTransition: boolean;
|
||||||
|
customTransition: boolean;
|
||||||
|
created(): void;
|
||||||
|
transition(enteringEl: HTMLElement, leavingEl: HTMLElement): Promise<boolean> | undefined;
|
||||||
|
getDuration(): 0 | undefined;
|
||||||
|
getDirection(): "forward" | "back";
|
||||||
|
beforeEnter(el: HTMLElement): void;
|
||||||
|
beforeLeave(el: HTMLElement): void;
|
||||||
|
leave(el: HTMLElement, done: (opts?: boolean) => void): void;
|
||||||
|
enter(_el: HTMLElement, done: () => void): void;
|
||||||
|
afterEnter(): void;
|
||||||
|
enterCancelled(): void;
|
||||||
|
afterLeave(): void;
|
||||||
|
leaveCancelled(): void;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
|
//# sourceMappingURL=ion-vue-router.vue?rollup-plugin-vue=script.d.ts.map
|
11
vue/types/framework-delegate.d.ts
vendored
Normal file
11
vue/types/framework-delegate.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { VueConstructor } from 'vue';
|
||||||
|
import { FrameworkDelegate, HTMLVueElement, WebpackFunction } from './interfaces';
|
||||||
|
export default class Delegate implements FrameworkDelegate {
|
||||||
|
vue: VueConstructor;
|
||||||
|
constructor(vue: VueConstructor);
|
||||||
|
attachViewToDom(parentElement: HTMLElement, component: HTMLElement | WebpackFunction | object | VueConstructor, opts?: object, classes?: string[]): Promise<HTMLElement>;
|
||||||
|
removeViewFromDom(_parentElement: HTMLElement, childElement: HTMLVueElement): Promise<void>;
|
||||||
|
vueController(component: WebpackFunction | object | VueConstructor): Promise<VueConstructor>;
|
||||||
|
vueComponent(controller: VueConstructor, opts?: object): import("vue/types/vue").CombinedVueInstance<import("vue/types/vue").Vue, object, object, object, Record<never, any>>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=framework-delegate.d.ts.map
|
4
vue/types/index.d.ts
vendored
Normal file
4
vue/types/index.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export { default as Ionic } from './ionic';
|
||||||
|
export { default as IonicAPI } from './api';
|
||||||
|
export { default as IonicVueRouter } from './router';
|
||||||
|
//# sourceMappingURL=index.d.ts.map
|
75
vue/types/interfaces.d.ts
vendored
Normal file
75
vue/types/interfaces.d.ts
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import IonicApi from './api';
|
||||||
|
import VueRouter from 'vue-router';
|
||||||
|
import { RouterOptions } from 'vue-router/types/router';
|
||||||
|
declare module 'vue/types/vue' {
|
||||||
|
interface Vue {
|
||||||
|
$ionic: IonicApi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
declare module 'vue-router/types/router' {
|
||||||
|
interface VueRouter {
|
||||||
|
direction: number;
|
||||||
|
directionOverride: number | null;
|
||||||
|
canGoBack(): boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export interface HTMLVueElement extends HTMLElement {
|
||||||
|
__vue__: Vue;
|
||||||
|
}
|
||||||
|
export interface VueWindow extends Window {
|
||||||
|
Vue: typeof Vue;
|
||||||
|
VueRouter: typeof VueRouter;
|
||||||
|
disableIonicTransitions: boolean;
|
||||||
|
}
|
||||||
|
export interface WebpackFunction extends Function {
|
||||||
|
cid: number;
|
||||||
|
}
|
||||||
|
export interface EsModule extends Object {
|
||||||
|
__esModule?: boolean;
|
||||||
|
[Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
export interface HTMLStencilElement extends HTMLElement {
|
||||||
|
componentOnReady(): Promise<this>;
|
||||||
|
componentOnReady(done: (el?: this) => void): void;
|
||||||
|
forceUpdate(): void;
|
||||||
|
}
|
||||||
|
export interface FrameworkDelegate {
|
||||||
|
attachViewToDom(parentElement: HTMLElement, component: HTMLElement | WebpackFunction | object | Vue, opts?: object, classes?: string[]): Promise<HTMLElement>;
|
||||||
|
removeViewFromDom(parentElement: HTMLElement, childElement: HTMLVueElement): Promise<void>;
|
||||||
|
}
|
||||||
|
export interface IonBackButton extends HTMLStencilElement {
|
||||||
|
defaultHref?: string;
|
||||||
|
}
|
||||||
|
export interface IonRouterOutlet extends HTMLStencilElement {
|
||||||
|
commit(enterinEl: HTMLElement, leavingEl: HTMLElement | undefined, opts?: object | undefined): Promise<boolean>;
|
||||||
|
}
|
||||||
|
export interface ApiCache {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
export interface RouterArgs extends RouterOptions {
|
||||||
|
direction: number;
|
||||||
|
viewCount: number;
|
||||||
|
}
|
||||||
|
export interface ProxyControllerInterface {
|
||||||
|
create(opts: object): Promise<HTMLElement>;
|
||||||
|
dismiss(): Promise<void>;
|
||||||
|
getTop(): Promise<HTMLElement>;
|
||||||
|
}
|
||||||
|
export interface ProxyDelegateOptions extends Object {
|
||||||
|
[key: string]: any;
|
||||||
|
delegate?: FrameworkDelegate;
|
||||||
|
}
|
||||||
|
export interface ProxyMenuControllerInterface {
|
||||||
|
open(menuId?: string): Promise<boolean>;
|
||||||
|
close(menuId?: string): Promise<boolean>;
|
||||||
|
toggle(menuId?: string): Promise<boolean>;
|
||||||
|
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement>;
|
||||||
|
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement>;
|
||||||
|
isOpen(menuId?: string): Promise<boolean>;
|
||||||
|
isEnabled(menuId?: string): Promise<boolean>;
|
||||||
|
get(menuId?: string): Promise<HTMLElement>;
|
||||||
|
getOpen(): Promise<HTMLElement>;
|
||||||
|
getMenus(): Promise<HTMLElement>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=interfaces.d.ts.map
|
8
vue/types/ionic.d.ts
vendored
Normal file
8
vue/types/ionic.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import '@ionic/core/css/ionic.bundle.css';
|
||||||
|
import 'ionicons/dist/collection/icon/icon.css';
|
||||||
|
import '@ionic/core/dist/ionic/svg';
|
||||||
|
declare const _default: {
|
||||||
|
init(): void;
|
||||||
|
};
|
||||||
|
export default _default;
|
||||||
|
//# sourceMappingURL=ionic.d.ts.map
|
5
vue/types/mixins/catch-ionic-go-back.d.ts
vendored
Normal file
5
vue/types/mixins/catch-ionic-go-back.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
export default class CatchIonicGoBack extends Vue {
|
||||||
|
catchIonicGoBack(event: Event): void;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=catch-ionic-go-back.d.ts.map
|
9
vue/types/proxy-controller.d.ts
vendored
Normal file
9
vue/types/proxy-controller.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { ProxyControllerInterface } from './interfaces';
|
||||||
|
export default class ProxyController implements ProxyControllerInterface {
|
||||||
|
tag: string;
|
||||||
|
constructor(tag: string);
|
||||||
|
create(opts?: object): Promise<HTMLElement>;
|
||||||
|
dismiss(): Promise<void>;
|
||||||
|
getTop(): Promise<HTMLElement>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=proxy-controller.d.ts.map
|
9
vue/types/proxy-delegate-controller.d.ts
vendored
Normal file
9
vue/types/proxy-delegate-controller.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import ProxyController from './proxy-controller';
|
||||||
|
import { FrameworkDelegate, ProxyDelegateOptions } from './interfaces';
|
||||||
|
export default class ProxyDelegateController extends ProxyController {
|
||||||
|
tag: string;
|
||||||
|
static delegate: FrameworkDelegate;
|
||||||
|
constructor(tag: string, delegate: FrameworkDelegate);
|
||||||
|
create(opts?: ProxyDelegateOptions): Promise<HTMLElement>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=proxy-delegate-controller.d.ts.map
|
16
vue/types/proxy-menu-controller.d.ts
vendored
Normal file
16
vue/types/proxy-menu-controller.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { ProxyMenuControllerInterface } from './interfaces';
|
||||||
|
export default class ProxyMenuController implements ProxyMenuControllerInterface {
|
||||||
|
tag: string;
|
||||||
|
constructor(tag: string);
|
||||||
|
open(menuId?: string): Promise<boolean>;
|
||||||
|
close(menuId?: string): Promise<boolean>;
|
||||||
|
toggle(menuId?: string): Promise<boolean>;
|
||||||
|
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement>;
|
||||||
|
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement>;
|
||||||
|
isOpen(menuId?: string): Promise<boolean>;
|
||||||
|
isEnabled(menuId?: string): Promise<boolean>;
|
||||||
|
get(menuId?: string): Promise<HTMLElement>;
|
||||||
|
getOpen(): Promise<HTMLElement>;
|
||||||
|
getMenus(): Promise<HTMLElement>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=proxy-menu-controller.d.ts.map
|
19
vue/types/router.d.ts
vendored
Normal file
19
vue/types/router.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import VueRouter, { Route } from 'vue-router';
|
||||||
|
import { PluginFunction } from 'vue';
|
||||||
|
import { RouterArgs } from './interfaces';
|
||||||
|
declare const _VueRouter: typeof VueRouter;
|
||||||
|
export default class Router extends _VueRouter {
|
||||||
|
direction: number;
|
||||||
|
directionOverride: number | null;
|
||||||
|
viewCount: number;
|
||||||
|
prevRouteStack: Route[];
|
||||||
|
history: any;
|
||||||
|
static installed: boolean;
|
||||||
|
static install: PluginFunction<never>;
|
||||||
|
constructor(args?: RouterArgs);
|
||||||
|
extendHistory(): void;
|
||||||
|
canGoBack(): boolean;
|
||||||
|
guessDirection(nextRoute: Route): number;
|
||||||
|
}
|
||||||
|
export {};
|
||||||
|
//# sourceMappingURL=router.d.ts.map
|
75
vue/types/types/interfaces.d.ts
vendored
Normal file
75
vue/types/types/interfaces.d.ts
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import Vue from 'vue';
|
||||||
|
import IonicApi from '../api';
|
||||||
|
import VueRouter from 'vue-router';
|
||||||
|
import { RouterOptions } from 'vue-router/types/router';
|
||||||
|
declare module 'vue/types/vue' {
|
||||||
|
interface Vue {
|
||||||
|
$ionic: IonicApi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
declare module 'vue-router/types/router' {
|
||||||
|
interface VueRouter {
|
||||||
|
direction: number;
|
||||||
|
directionOverride: number | null;
|
||||||
|
canGoBack(): boolean;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export interface HTMLVueElement extends HTMLElement {
|
||||||
|
__vue__: Vue;
|
||||||
|
}
|
||||||
|
export interface VueWindow extends Window {
|
||||||
|
Vue: typeof Vue;
|
||||||
|
VueRouter: typeof VueRouter;
|
||||||
|
disableIonicTransitions: boolean;
|
||||||
|
}
|
||||||
|
export interface WebpackFunction extends Function {
|
||||||
|
cid: number;
|
||||||
|
}
|
||||||
|
export interface EsModule extends Object {
|
||||||
|
__esModule?: boolean;
|
||||||
|
[Symbol.toStringTag]: string;
|
||||||
|
}
|
||||||
|
export interface HTMLStencilElement extends HTMLElement {
|
||||||
|
componentOnReady(): Promise<this>;
|
||||||
|
componentOnReady(done: (el?: this) => void): void;
|
||||||
|
forceUpdate(): void;
|
||||||
|
}
|
||||||
|
export interface FrameworkDelegate {
|
||||||
|
attachViewToDom(parentElement: HTMLElement, component: HTMLElement | WebpackFunction | object | Vue, opts?: object, classes?: string[]): Promise<HTMLElement>;
|
||||||
|
removeViewFromDom(parentElement: HTMLElement, childElement: HTMLVueElement): Promise<void>;
|
||||||
|
}
|
||||||
|
export interface IonBackButton extends HTMLStencilElement {
|
||||||
|
defaultHref?: string;
|
||||||
|
}
|
||||||
|
export interface IonRouterOutlet extends HTMLStencilElement {
|
||||||
|
commit(enterinEl: HTMLElement, leavingEl: HTMLElement | undefined, opts?: object | undefined): Promise<boolean>;
|
||||||
|
}
|
||||||
|
export interface ApiCache {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
export interface RouterArgs extends RouterOptions {
|
||||||
|
direction: number;
|
||||||
|
viewCount: number;
|
||||||
|
}
|
||||||
|
export interface ProxyControllerInterface {
|
||||||
|
create(opts: object): Promise<HTMLElement>;
|
||||||
|
dismiss(): Promise<void>;
|
||||||
|
getTop(): Promise<HTMLElement>;
|
||||||
|
}
|
||||||
|
export interface ProxyDelegateOptions extends Object {
|
||||||
|
[key: string]: any;
|
||||||
|
delegate: FrameworkDelegate;
|
||||||
|
}
|
||||||
|
export interface ProxyMenuControllerInterface {
|
||||||
|
open(menuId?: string): Promise<boolean>;
|
||||||
|
close(menuId?: string): Promise<boolean>;
|
||||||
|
toggle(menuId?: string): Promise<boolean>;
|
||||||
|
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement>;
|
||||||
|
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLElement>;
|
||||||
|
isOpen(menuId?: string): Promise<boolean>;
|
||||||
|
isEnabled(menuId?: string): Promise<boolean>;
|
||||||
|
get(menuId?: string): Promise<HTMLElement>;
|
||||||
|
getOpen(): Promise<HTMLElement>;
|
||||||
|
getMenus(): Promise<HTMLElement>;
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=interfaces.d.ts.map
|
Reference in New Issue
Block a user