chore: refactor vue (#16587)

This commit is contained in:
Mike Hartington
2018-12-04 16:13:55 -05:00
committed by GitHub
parent 9c8c6507fc
commit 87b25960c4
43 changed files with 599 additions and 2165 deletions

View File

@ -0,0 +1,9 @@
import { ActionSheetOptions } from '@ionic/core';
import { OverlayBaseController } from '../util';
export const CTRL = 'ion-action-sheet-controller';
export class ActionSheetController extends OverlayBaseController<ActionSheetOptions, HTMLIonActionSheetElement> {
constructor() {
super(CTRL);
}
}

View File

@ -0,0 +1,9 @@
import { AlertOptions } from '@ionic/core';
import { OverlayBaseController } from '../util';
export const CTRL = 'ion-alert-controller';
export class AlertController extends OverlayBaseController<AlertOptions, HTMLIonAlertElement> {
constructor() {
super(CTRL);
}
}

View File

@ -0,0 +1,7 @@
export { ActionSheetController } from './action-sheet-controller';
export { AlertController } from './alert-controller';
export { LoadingController } from './loading-controller';
export { MenuController } from './menu-controller';
export { ModalController } from './modal-controller';
export { PopoverController } from './popover-controller';
export { ToastController } from './toast-controller';

View File

@ -0,0 +1,8 @@
import { LoadingOptions } from '@ionic/core';
import { OverlayBaseController } from '../util';
export class LoadingController extends OverlayBaseController<LoadingOptions, HTMLIonLoadingElement> {
constructor() {
super('ion-loading-controller');
}
}

View File

@ -0,0 +1,101 @@
import { proxyMethod } from '../util';
export const CTRL = 'ion-menu-controller';
export class MenuController {
/**
* Programmatically open the Menu.
* @param [menuId] Optionally get the menu by its id, or side.
* @return returns a promise when the menu is fully opened
*/
open(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'open', menuId);
}
/**
* Programmatically close the Menu. If no `menuId` is given as the first
* argument then it'll close any menu which is open. If a `menuId`
* is given then it'll close that exact menu.
* @param [menuId] Optionally get the menu by its id, or side.
* @return returns a promise when the menu is fully closed
*/
close(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'close', menuId);
}
/**
* Toggle the menu. If it's closed, it will open, and if opened, it
* will close.
* @param [menuId] Optionally get the menu by its id, or side.
* @return returns a promise when the menu has been toggled
*/
toggle(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'toggle', menuId);
}
/**
* Used to enable or disable a menu. For example, there could be multiple
* left menus, but only one of them should be able to be opened at the same
* time. If there are multiple menus on the same side, then enabling one menu
* will also automatically disable all the others that are on the same side.
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns the instance of the menu, which is useful for chaining.
*/
enable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, 'enable', shouldEnable, menuId);
}
/**
* Used to enable or disable the ability to swipe open the menu.
* @param shouldEnable True if it should be swipe-able, false if not.
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns the instance of the menu, which is useful for chaining.
*/
swipeEnable(shouldEnable: boolean, menuId?: string): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, 'swipeEnable', shouldEnable, menuId);
}
/**
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns true if the specified menu is currently open, otherwise false.
* If the menuId is not specified, it returns true if ANY menu is currenly open.
*/
isOpen(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'isOpen', menuId);
}
/**
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns true if the menu is currently enabled, otherwise false.
*/
isEnabled(menuId?: string): Promise<boolean> {
return proxyMethod(CTRL, 'isEnabled', menuId);
}
/**
* Used to get a menu instance. If a `menuId` is not provided then it'll
* return the first menu found. If a `menuId` is `left` or `right`, then
* it'll return the enabled menu on that side. Otherwise, if a `menuId` is
* provided, then it'll try to find the menu using the menu's `id`
* property. If a menu is not found then it'll return `null`.
* @param [menuId] Optionally get the menu by its id, or side.
* @return Returns the instance of the menu if found, otherwise `null`.
*/
get(menuId?: string): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, 'get', menuId);
}
/**
* @return Returns the instance of the menu already opened, otherwise `null`.
*/
getOpen(): Promise<HTMLIonMenuElement> {
return proxyMethod(CTRL, 'getOpen');
}
/**
* @return Returns an array of all menu instances.
*/
getMenus(): Promise<HTMLIonMenuElement[]> {
return proxyMethod(CTRL, 'getMenus');
}
}

View File

@ -0,0 +1,20 @@
import { ModalOptions } from '@ionic/core';
import { OverlayBaseController } from '../util';
import { VueDelegate } from './vue-delegate';
export const CTRL = 'ion-modal-controller';
export class ModalController extends OverlayBaseController<ModalOptions, HTMLIonModalElement> {
constructor(
private delegate: VueDelegate
) {
super(CTRL);
}
create(opts: ModalOptions): Promise<HTMLIonModalElement> {
return super.create({
...opts,
delegate: this.delegate
});
}
}

View File

@ -0,0 +1,9 @@
import { PickerOptions } from '@ionic/core';
import { OverlayBaseController } from '../util';
export const CTRL = 'ion-picker-controller';
export class PickerController extends OverlayBaseController<PickerOptions, HTMLIonPickerElement> {
constructor() {
super(CTRL);
}
}

View File

@ -0,0 +1,20 @@
import { PopoverOptions } from '@ionic/core';
import { OverlayBaseController } from '../util';
import { VueDelegate } from './vue-delegate';
export const CTRL = 'ion-modal-controller';
export class PopoverController extends OverlayBaseController<PopoverOptions, HTMLIonPopoverElement> {
constructor(
private delegate: VueDelegate
) {
super(CTRL);
}
create(opts: PopoverOptions): Promise<HTMLIonPopoverElement> {
return super.create({
...opts,
delegate: this.delegate
});
}
}

View File

@ -0,0 +1,8 @@
import { ToastOptions } from '@ionic/core';
import { OverlayBaseController } from '../util';
export class ToastController extends OverlayBaseController<ToastOptions, HTMLIonToastElement> {
constructor() {
super('ion-toast-controller');
}
}

View File

@ -0,0 +1,97 @@
import { VueConstructor, default as Vue } from 'vue';
import { FrameworkDelegate, ViewLifecycle } from '@ionic/core';
import { EsModule, HTMLVueElement, WebpackFunction } from '../interfaces';
// Handle creation of sync and async components
function createVueComponent(vue: VueConstructor, component: WebpackFunction | object | VueConstructor): Promise<VueConstructor> {
return Promise.resolve(
typeof component === 'function' && (component as WebpackFunction).cid === undefined
? (component as WebpackFunction)().then((cmp: any) => vue.extend(isESModule(cmp) ? cmp.default : cmp))
: vue.extend(component)
);
}
export class VueDelegate implements FrameworkDelegate {
constructor(
public vue: VueConstructor,
public $root: Vue
) {}
// 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);
bindLifecycleEvents(component, parentElement);
return Promise.resolve(component as HTMLElement);
}
// Get the Vue controller
return createVueComponent(this.vue, component).then((Component: VueConstructor) => {
const componentInstance = new Component({
propsData: opts
});
componentInstance.$mount();
// Add any classes to the Vue component's root element
addClasses(componentInstance.$el, classes);
// Append the Vue component to DOM
parentElement.appendChild(componentInstance.$el);
return componentInstance.$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();
}
}
const LIFECYCLES = [
ViewLifecycle.WillEnter,
ViewLifecycle.DidEnter,
ViewLifecycle.WillLeave,
ViewLifecycle.DidLeave,
ViewLifecycle.WillUnload
];
export function bindLifecycleEvents(instance: any, element: HTMLElement) {
LIFECYCLES.forEach(eventName => {
element.addEventListener(eventName, (ev: any) => {
if (typeof instance[eventName] === 'function') {
instance[eventName](ev.detail);
}
});
});
}
// 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);
}
}