Skip to content

Commit

Permalink
fix(modal): parent page invalid hierarchy handling [extended] (#5966)
Browse files Browse the repository at this point in the history
* fix(modal): parent page invalid hierarchy handling

* refactor(modals): Refactor safe guard in show/hide modal
  • Loading branch information
Alexander Vakrilov committed Jun 20, 2018
1 parent 4b5754a commit b5b8d51
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 19 deletions.
12 changes: 10 additions & 2 deletions tns-core-modules/ui/core/bindable/bindable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,19 @@

import { ViewBase } from "../view-base";
import { Observable, WrappedValue, PropertyChangeData, EventData } from "../../../data/observable";
import { isEnabled as traceEnabled, write as traceWrite, categories as traceCategories, notifyEvent as traceNotifyEvent, messageType as traceMessageType, isCategorySet } from "../../../trace";
import {
isEnabled as traceEnabled,
write as traceWrite,
error as traceError,
categories as traceCategories,
notifyEvent as traceNotifyEvent,
messageType as traceMessageType,
isCategorySet } from "../../../trace";

export {
Observable, WrappedValue, PropertyChangeData, EventData,
traceEnabled, traceWrite, traceCategories, traceNotifyEvent, traceMessageType, isCategorySet
traceEnabled, traceWrite, traceError, traceCategories, traceNotifyEvent,
traceMessageType, isCategorySet
};

/**
Expand Down
12 changes: 10 additions & 2 deletions tns-core-modules/ui/core/bindable/bindable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,23 @@ import { Observable, WrappedValue, PropertyChangeData, EventData } from "../../.
import { addWeakEventListener, removeWeakEventListener } from "../weak-event-listener";
import { bindingConstants, parentsRegex } from "../../builder/binding-builder";
import { escapeRegexSymbols } from "../../../utils/utils";
import { isEnabled as traceEnabled, write as traceWrite, categories as traceCategories, notifyEvent as traceNotifyEvent, isCategorySet, messageType as traceMessageType } from "../../../trace";
import {
isEnabled as traceEnabled,
write as traceWrite,
error as traceError,
categories as traceCategories,
notifyEvent as traceNotifyEvent,
isCategorySet,
messageType as traceMessageType
} from "../../../trace";
import * as types from "../../../utils/types";

import * as applicationCommon from "../../../application/application-common";
import * as polymerExpressions from "../../../js-libs/polymer-expressions";

export {
Observable, WrappedValue, PropertyChangeData, EventData,
traceEnabled, traceWrite, traceCategories, traceNotifyEvent, traceMessageType, isCategorySet
traceEnabled, traceWrite, traceError, traceCategories, traceNotifyEvent, traceMessageType, isCategorySet
};

const contextKey = "context";
Expand Down
6 changes: 5 additions & 1 deletion tns-core-modules/ui/core/view/view.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,11 @@ export const isEnabledProperty: Property<View, boolean>;
export const isUserInteractionEnabledProperty: Property<View, boolean>;

export namespace ios {
export function getParentWithViewController(parent: View): View
/**
* Returns a view with viewController or undefined if no such found along the view's parent chain.
* @param view The view form which to start the search.
*/
export function getParentWithViewController(view: View): View
export function isContentScrollable(controller: any /* UIViewController */, owner: View): boolean
export function updateAutoAdjustScrollInsets(controller: any /* UIViewController */, owner: View): void
export function updateConstraints(controller: any /* UIViewController */, owner: View): void;
Expand Down
37 changes: 24 additions & 13 deletions tns-core-modules/ui/core/view/view.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ViewBase } from "../view-base";

import {
ViewCommon, layout, isEnabledProperty, originXProperty, originYProperty, automationTextProperty, isUserInteractionEnabledProperty,
traceEnabled, traceWrite, traceCategories, traceMessageType
traceEnabled, traceWrite, traceCategories, traceError, traceMessageType
} from "./view-common";

import { ios as iosBackground, Background } from "../../styling/background";
Expand Down Expand Up @@ -309,7 +309,19 @@ export class View extends ViewCommon {
}

protected _showNativeModalView(parent: View, context: any, closeCallback: Function, fullscreen?: boolean, animated?: boolean, stretched?: boolean) {
let parentWithController = ios.getParentWithViewController(parent);
const parentWithController = ios.getParentWithViewController(parent);
if (!parentWithController) {
traceWrite(`Could not find parent with viewController for ${parent} while showing modal view.`,
traceCategories.ViewHierarchy, traceMessageType.error)
return;
}

const parentController = parentWithController.viewController;
if (!parentController.view || !parentController.view.window) {
traceWrite("Parent page is not part of the window hierarchy. Close the current modal page before showing another one!",
traceCategories.ViewHierarchy, traceMessageType.error);
return;
}

super._showNativeModalView(parentWithController, context, closeCallback, fullscreen, stretched);
let controller = this.viewController;
Expand All @@ -326,11 +338,6 @@ export class View extends ViewCommon {

this._setupAsRootView({});

const parentController = parentWithController.viewController;
if (!parentController.view.window) {
throw new Error("Parent page is not part of the window hierarchy. Close the current modal page before showing another one!");
}

if (fullscreen) {
controller.modalPresentationStyle = UIModalPresentationStyle.FullScreen;
} else {
Expand All @@ -346,7 +353,8 @@ export class View extends ViewCommon {
parentController.presentViewControllerAnimatedCompletion(controller, animated, null);
const transitionCoordinator = iosUtils.getter(parentController, parentController.transitionCoordinator);
if (transitionCoordinator) {
UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion.call(transitionCoordinator, null, () => this._raiseShownModallyEvent());
UIViewControllerTransitionCoordinator.prototype.animateAlongsideTransitionCompletion
.call(transitionCoordinator, null, () => this._raiseShownModallyEvent());
} else {
// Apparently iOS 9+ stops all transitions and animations upon application suspend and transitionCoordinator becomes null here in this case.
// Since we are not waiting for any transition to complete, i.e. transitionCoordinator is null, we can directly raise our shownModally event.
Expand All @@ -356,6 +364,11 @@ export class View extends ViewCommon {
}

protected _hideNativeModalView(parent: View) {
if (!parent || !parent.viewController) {
traceError("Trying to hide modal view but no parent with viewController specified.")
return;
}

const parentController = parent.viewController;
const animated = (<any>this.viewController).animated;

Expand Down Expand Up @@ -582,14 +595,12 @@ export class CustomLayoutView extends View {
}

export namespace ios {
export function getParentWithViewController(parent: View): View {
let view = parent;
let controller = view.viewController;
while (!controller) {
export function getParentWithViewController(view: View): View {
while (view && !view.viewController) {
view = view.parent as View;
controller = view.viewController;
}

// Note: Might return undefined if no parent with viewController is found
return view;
}

Expand Down
3 changes: 2 additions & 1 deletion tns-core-modules/ui/dialogs/dialogs.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ function showUIAlertController(alertController: UIAlertController) {
if (view.ios instanceof UIViewController) {
viewController = view.ios;
} else {
viewController = iosView.getParentWithViewController(view).viewController;
const parentWithController = iosView.getParentWithViewController(view);
viewController = parentWithController ? parentWithController.viewController : undefined;
}
}

Expand Down

0 comments on commit b5b8d51

Please sign in to comment.