mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 19:57:22 +08:00
refactor(framework-delegate): wrap user element with ion-page for modal and nav
This commit is contained in:
@ -1,7 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
ApplicationRef,
|
ApplicationRef,
|
||||||
ComponentFactoryResolver,
|
ComponentFactoryResolver,
|
||||||
ComponentRef,
|
|
||||||
Injectable,
|
Injectable,
|
||||||
Injector,
|
Injector,
|
||||||
NgZone,
|
NgZone,
|
||||||
@ -12,7 +11,7 @@ import {
|
|||||||
import { getProviders } from '../di/di';
|
import { getProviders } from '../di/di';
|
||||||
import { AngularMountingData } from '../types/interfaces';
|
import { AngularMountingData } from '../types/interfaces';
|
||||||
|
|
||||||
const elementToComponentRefMap = new Map<HTMLElement, ComponentRef<any>>();
|
const elementToComponentRefMap = new Map<HTMLElement, AngularMountingData>();
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AngularComponentMounter {
|
export class AngularComponentMounter {
|
||||||
@ -20,14 +19,14 @@ export class AngularComponentMounter {
|
|||||||
constructor(private defaultCfr: ComponentFactoryResolver, private zone: NgZone, private appRef: ApplicationRef) {
|
constructor(private defaultCfr: ComponentFactoryResolver, private zone: NgZone, private appRef: ApplicationRef) {
|
||||||
}
|
}
|
||||||
|
|
||||||
attachViewToDom(parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type<any>, componentResolveFactory: ComponentFactoryResolver, injector: Injector, data: any, classesToAdd: string[], wrapUserTemplateInIonPage: boolean): Promise<AngularMountingData> {
|
attachViewToDom(parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type<any>, componentResolveFactory: ComponentFactoryResolver, injector: Injector, data: any, classesToAdd: string[], wrapUserComponentInIonPage: boolean): Promise<AngularMountingData> {
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.zone.run(() => {
|
this.zone.run(() => {
|
||||||
|
|
||||||
const crf = componentResolveFactory ? componentResolveFactory : this.defaultCfr;
|
const crf = componentResolveFactory ? componentResolveFactory : this.defaultCfr;
|
||||||
|
|
||||||
const mountingData = attachViewToDom(crf, parentElement, hostElement, componentToMount, injector, this.appRef, data, classesToAdd, wrapUserTemplateInIonPage);
|
const mountingData = attachViewToDom(crf, parentElement, hostElement, componentToMount, injector, this.appRef, data, classesToAdd, wrapUserComponentInIonPage);
|
||||||
resolve(mountingData);
|
resolve(mountingData);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -45,16 +44,17 @@ export class AngularComponentMounter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement) {
|
export function removeViewFromDom(parentElement: HTMLElement, childElement: HTMLElement) {
|
||||||
const componentRef = elementToComponentRefMap.get(childElement);
|
const mountingData = elementToComponentRefMap.get(childElement);
|
||||||
if (componentRef) {
|
if (mountingData) {
|
||||||
componentRef.destroy();
|
const componentParent = mountingData.element.parentNode;
|
||||||
if (parentElement.contains(childElement)) {
|
mountingData.componentRef.destroy();
|
||||||
parentElement.removeChild(childElement);
|
if (mountingData.wrapUserComponentInIonPage && parentElement.contains(componentParent) ) {
|
||||||
|
parentElement.removeChild(componentParent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attachViewToDom(crf: ComponentFactoryResolver, parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type<any>, injector: Injector, appRef: ApplicationRef, data: any, classesToAdd: string[], wrapUserTemplateInIonPage: boolean): AngularMountingData {
|
export function attachViewToDom(crf: ComponentFactoryResolver, parentElement: HTMLElement, hostElement: HTMLElement, componentToMount: Type<any>, injector: Injector, appRef: ApplicationRef, data: any, classesToAdd: string[], wrapUserComponentInIonPage: boolean): AngularMountingData {
|
||||||
|
|
||||||
const componentProviders = ReflectiveInjector.resolve(getProviders(parentElement, data));
|
const componentProviders = ReflectiveInjector.resolve(getProviders(parentElement, data));
|
||||||
const componentFactory = crf.resolveComponentFactory(componentToMount);
|
const componentFactory = crf.resolveComponentFactory(componentToMount);
|
||||||
@ -62,32 +62,34 @@ export function attachViewToDom(crf: ComponentFactoryResolver, parentElement: HT
|
|||||||
hostElement = document.createElement(componentFactory.selector);
|
hostElement = document.createElement(componentFactory.selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mountingElement = hostElement;
|
|
||||||
if (wrapUserTemplateInIonPage) {
|
|
||||||
const ionPageElement = document.createElement('ion-page');
|
|
||||||
hostElement.appendChild(ionPageElement);
|
|
||||||
mountingElement = ionPageElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
const childInjector = ReflectiveInjector.fromResolvedProviders(componentProviders, injector);
|
const childInjector = ReflectiveInjector.fromResolvedProviders(componentProviders, injector);
|
||||||
const componentRef = componentFactory.create(childInjector, [], mountingElement);
|
const componentRef = componentFactory.create(childInjector, [], hostElement);
|
||||||
for (const clazz of classesToAdd) {
|
for (const clazz of classesToAdd) {
|
||||||
hostElement.classList.add(clazz);
|
hostElement.classList.add(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
parentElement.appendChild(hostElement);
|
const elementToAppend = wrapUserComponentInIonPage ? getIonPageElement(hostElement) : hostElement;
|
||||||
|
parentElement.appendChild(elementToAppend);
|
||||||
|
|
||||||
appRef.attachView(componentRef.hostView);
|
appRef.attachView(componentRef.hostView);
|
||||||
|
|
||||||
elementToComponentRefMap.set(hostElement, componentRef);
|
const mountingData = {
|
||||||
|
|
||||||
return {
|
|
||||||
componentFactory,
|
componentFactory,
|
||||||
childInjector,
|
childInjector,
|
||||||
componentRef,
|
componentRef,
|
||||||
instance: componentRef.instance,
|
instance: componentRef.instance,
|
||||||
angularHostElement: componentRef.location.nativeElement,
|
angularHostElement: componentRef.location.nativeElement,
|
||||||
element: hostElement,
|
element: hostElement,
|
||||||
|
wrapUserComponentInIonPage
|
||||||
};
|
};
|
||||||
|
|
||||||
|
elementToComponentRefMap.set(hostElement, mountingData);
|
||||||
|
|
||||||
|
return mountingData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getIonPageElement(hostElement: HTMLElement) {
|
||||||
|
const page = document.createElement('ion-page');
|
||||||
|
page.appendChild(hostElement);
|
||||||
|
return page;
|
||||||
|
}
|
@ -12,4 +12,5 @@ export interface AngularMountingData extends FrameworkMountingData {
|
|||||||
componentRef?: ComponentRef<any>;
|
componentRef?: ComponentRef<any>;
|
||||||
instance?: any;
|
instance?: any;
|
||||||
angularHostElement?: HTMLElement;
|
angularHostElement?: HTMLElement;
|
||||||
|
wrapUserComponentInIonPage?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
import { FrameworkDelegate, FrameworkMountingData, } from '../index';
|
import { FrameworkDelegate, FrameworkMountingData, } from '../index';
|
||||||
import { isString } from './helpers';
|
import { isElementModal, isElementNav, isString } from './helpers';
|
||||||
|
|
||||||
export class DomFrameworkDelegate implements FrameworkDelegate {
|
export class DomFrameworkDelegate implements FrameworkDelegate {
|
||||||
|
|
||||||
attachViewToDom(parentElement: HTMLElement, tagOrElement: string | HTMLElement, propsOrDataObj: any = {}, classesToAdd: string[] = []): Promise<FrameworkMountingData> {
|
attachViewToDom(parentElement: HTMLElement, tagOrElement: string | HTMLElement, propsOrDataObj: any = {}, classesToAdd: string[] = []): Promise<FrameworkMountingData> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const usersElement = (isString(tagOrElement) ? document.createElement(tagOrElement) : tagOrElement) as HTMLElement;
|
const usersElement = (isString(tagOrElement) ? document.createElement(tagOrElement) : tagOrElement) as HTMLElement;
|
||||||
|
|
||||||
Object.assign(usersElement, propsOrDataObj);
|
Object.assign(usersElement, propsOrDataObj);
|
||||||
|
|
||||||
if (classesToAdd.length) {
|
if (classesToAdd.length) {
|
||||||
for (const clazz of classesToAdd) {
|
for (const clazz of classesToAdd) {
|
||||||
usersElement.classList.add(clazz);
|
usersElement.classList.add(clazz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parentElement.appendChild(usersElement);
|
|
||||||
|
const elementToAppend = shouldWrapInIonPage(parentElement) ? createIonPageAndAppendUserElement(usersElement) : usersElement;
|
||||||
|
parentElement.appendChild(elementToAppend);
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
element: usersElement
|
element: elementToAppend
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -27,3 +30,13 @@ export class DomFrameworkDelegate implements FrameworkDelegate {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function shouldWrapInIonPage(element: HTMLElement) {
|
||||||
|
return isElementModal(element) || isElementNav(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createIonPageAndAppendUserElement(userElement: HTMLElement) {
|
||||||
|
const wrappingElement = document.createElement('ion-page');
|
||||||
|
wrappingElement.appendChild(userElement);
|
||||||
|
return wrappingElement;
|
||||||
|
}
|
||||||
|
@ -24,6 +24,14 @@ export function isStringOrNumber(v: any): v is (string | number) { return isStri
|
|||||||
|
|
||||||
export function isBlank(val: any): val is null { return val === undefined || val === null; }
|
export function isBlank(val: any): val is null { return val === undefined || val === null; }
|
||||||
|
|
||||||
|
export function isElementNav(element: HTMLElement) {
|
||||||
|
return element.tagName.toUpperCase() === 'ION-NAV';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isElementModal(element: HTMLElement) {
|
||||||
|
return element.classList.contains('modal-wrapper');
|
||||||
|
}
|
||||||
|
|
||||||
/** @hidden */
|
/** @hidden */
|
||||||
export function isCheckedProperty(a: any, b: any): boolean {
|
export function isCheckedProperty(a: any, b: any): boolean {
|
||||||
if (a === undefined || a === null || a === '') {
|
if (a === undefined || a === null || a === '') {
|
||||||
|
@ -2,10 +2,9 @@ import React from 'react';
|
|||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
import { FrameworkDelegate } from '@ionic/core';
|
import { FrameworkDelegate } from '@ionic/core';
|
||||||
|
import { isElementModal, isElementNav } from './utils/helpers';
|
||||||
|
|
||||||
export function attachViewToDom(parentElement: HTMLElement, reactComponent: any, propsOrData: any, classesToAdd: string[]) {
|
export function attachViewToDom(parentElement: HTMLElement, reactComponent: any, propsOrData: any, classesToAdd: string[]) {
|
||||||
console.log('parentElement: ', parentElement);
|
|
||||||
console.log('reactComponent: ', reactComponent);
|
|
||||||
const wrappingDiv = shouldWrapInIonPage(parentElement) ? document.createElement('ion-page') : document.createElement('div');
|
const wrappingDiv = shouldWrapInIonPage(parentElement) ? document.createElement('ion-page') : document.createElement('div');
|
||||||
if (classesToAdd) {
|
if (classesToAdd) {
|
||||||
for (const clazz of classesToAdd) {
|
for (const clazz of classesToAdd) {
|
||||||
@ -41,8 +40,5 @@ export { Delegate }
|
|||||||
|
|
||||||
|
|
||||||
export function shouldWrapInIonPage(element: HTMLElement) {
|
export function shouldWrapInIonPage(element: HTMLElement) {
|
||||||
if (element.tagName.toUpperCase() === 'ION-NAV' || element.classList.contains('modal-wrapper')) {
|
return isElementModal(element) || isElementNav(element);
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
@ -7,4 +7,12 @@ export function getOrAppendElement(tagName: string): Element {
|
|||||||
const tmp = document.createElement(tagName);
|
const tmp = document.createElement(tagName);
|
||||||
document.body.appendChild(tmp);
|
document.body.appendChild(tmp);
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isElementNav(element: HTMLElement) {
|
||||||
|
return element.tagName.toUpperCase() === 'ION-NAV';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isElementModal(element: HTMLElement) {
|
||||||
|
return element.classList.contains('modal-wrapper');
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user